我有一些代码,它抛出了。我不明白为什么。
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
是否有一些静态解析的编译器魔术?生成的IL提示了这一点。
callvirt System.String.Substring
是否可以在动态声明的表达式上使用范围索引?
答案 0 :(得分:3)
Range Indexing在C#8.0中发布,它不支持动态,无法将其转换为其他代码(在这种情况下为text.SubString()
),这意味着无法在运行时解析。在Lambda Tuple C#8.0中,dynamic
也遇到了同样的问题。
您可以在代码下方的右侧选中how this translation work。
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]
}
}
range indexing
在编译过程中被IDE转换为substring()
,因此实际上并未在string class
中实现,因此解释了为什么只声明单个索引d[1]
的原因。
简而言之,我们有2个选择
选项1:实际上,dynamic
正在使用Reflection技术来解析和抓取它是否在变量method ...的范围内,这意味着在Reflection中不会再出现任何翻译代码。因此,将dynamic
转换为特定类型将基本上帮助IDE进行转换。
选项2:对象应像RangeIndexer
类那样实现,以用作动态类型,以确保反射可以抓取它。但是几乎经典类型都不支持,因此只能与您自己的模型一起使用。
答案 1 :(得分:2)
有一些静态解决的编译器魔术吗?
是的,有。
具有范围(this[System.Range]
或this[start..end]
)的索引器受两种方式支持:显式和隐式。
明确 。如果类型声明了索引器this[System.Range]
,则每当我们使用符号this[start..end]
时都将使用此索引器。编译器将表达式start..end
转换为适当的System.Range
对象,并生成调用索引器this[System.Range]
的代码。
简单地 。如果type不包含索引器this[System.Range]
,则可以隐式支持范围索引。为了能够隐式支持范围索引,类型必须满足以下条件:
Length
或Count
属性。Slice(start, end)
参数的int
方法。类型string
是一种特殊情况;用于string
类型的方法Substring
代替Slice
。如果类型满足这些条件,则当我们使用符号this[start..end]
时,编译器会生成调用方法Slice(start, end)
(或Substring(start, end)
表示string
)的代码。
有关更多详细信息,请参见C# specification: Ranges。
因此string
类型隐式支持范围索引。
考虑下一个代码示例:
dynamic d = "asdf";
Console.WriteLine(d[1..3]);
在编译期间无法确定dynamic
是指支持范围索引的对象。因此,编译器不会生成调用方法Substring
的代码。而是生成调用索引器this[System.Range]
的代码。 string
类型不包含此类索引器,因此将生成RuntimeBinderException
。