Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't range indexing work on dynamics

Tags:

c#

c#-8.0

I have some code, and it throws. I don't understand why.

string s="asdf";
Console.WriteLine(s[1..3]);

dynamic d="asdf";
Console.WriteLine(d[1..3]); // throws 
// RuntimeBinderException: The best overloaded method match for 'string.this[int]' has some invalid arguments

Is there some statically resolved compiler magic? The generated IL suggests this.

callvirt    System.String.Substring

Is there any way to use range indexing on dynamically declared expressions?

like image 562
recursive Avatar asked Oct 21 '25 08:10

recursive


1 Answers

Range Indexing is released in C# 8.0 and it doesn't support for dynamic, it cannot be translated to another code (in this case is text.SubString()) which means cannot resolve at runtime. I encountered the same problem with dynamic in Lambda Tuple C# 8.0 also.

You might check how this translation work on the right side below code.

public class MyClass {
    public class RangeIndexer
    {
        public string MyString { get; set; }
        public char this[int index] { get => MyString[index]; }
        public string this[Range range] { get => MyString[range]; }
    }

    public void Main() {
        string s = "asdf";
        Console.WriteLine(s[1..3]); // Translate to text.SubString()

        dynamic d = "asdf";
        Console.WriteLine("Index: " + d[1]); // Address to this[int]
        //Console.WriteLine("Range1: " + d[1..3]); // Cannot translate to text.SubString() => Crashed
        Console.WriteLine("Range2: " + d.Substring(1, 2)); // Local method of string
        Console.WriteLine("Range3: " + $"{d}"[1..3]); // Cast as string and translate like Range1

        dynamic rangeIndexer = new RangeIndexer();
        rangeIndexer.MyString = "asdf";
        Console.WriteLine("Range4: " + rangeIndexer[1..3]); // Address to this[range]
    }
}

The range indexing is translated to substring() by IDE during compilation so it's not actually implemented in string class, therefore it's explained why only single indexing d[1] worked because it's declared.

enter image description here

So in short, we have 2 options

Option 1: In fact, dynamic is using Reflection technical to resolve and grab if it's in scope of the variable, method,.. that means no more translation codes will occur in Reflection. Thus, casting dynamic to specific type would help IDE translate them basically.

Option 2: Object should implement like RangeIndexer class to work as dynamic type which make sure the Reflection could grab it. But almost classic types don't support so it only works with your own model.

like image 176
Tấn Nguyên Avatar answered Oct 22 '25 23:10

Tấn Nguyên



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!