考虑以下代码:
static void Main(string[] args)
{
var ints=new List<int> {10,11,22};
Something(ints);//Output:Count is:3
Something(new int[10]); //'System.Array' does not contain
// a definition for 'Count'
Console.ReadLine();
}
static void Something(ICollection collection)
{
dynamic dynamic = collection;
Console.WriteLine("Count is:{0}", dynamic.Count);
}
传递List时,一切都好。但是当传递数组并转换为动态时,我会收到此错误:'System.Array' does not contain a definition for 'Count'
。
我知道我的解决方案是什么,但我想知道为什么编译器有这种行为?
答案 0 :(得分:13)
Something(new int[10]);
static void Something(ICollection collection)
{
//The dynamic keyword tells the compilier to look at the underlying information
//at runtime to determine the variable's type. In this case, the underlying
//information suggests that dynamic should be an array because the variable you
//passed in is an array. Then it'll try to call Array.Count.
dynamic dynamic = collection;
Console.WriteLine("Count is:{0}", dynamic.Count);
//If you check the type of variable, you'll see that it is an ICollection because
//that's what type this function expected. Then this code will try to call
//ICollection.Count
var variable = collection;
Console.WriteLine("Count is:{0}", variable.Count);
}
现在我们可以理解为什么dynamic.Count试图调用System.Array.Count。但是,当Array实现具有Count方法的System.Collections.ICollection时,仍然不清楚为什么没有定义Array.Count。实际上,Array确实正确地实现了ICollection,它确实有一个Count方法。但是,如果没有将Array显式地转换为ICollection,则Array.Count的使用者无权访问Count属性。 Array.Count使用称为explicit interface implementation的模式实现,其中Array.Count是为ICollection显式实现的。并且您只能通过将变量转换为具有此模式的ICollection来访问count方法。这反映在docs for Array中。查找“显式接口实现”部分。
var myArray = new int[10];
//Won't work because Array.Count is implemented with explicit interface implementation
//where the interface is ICollection
Console.Write(myArray.Count);
//Will work because we've casted the Array to an ICollection
Console.Write(((ICollection)myArray).Count);
答案 1 :(得分:3)
动态在内部使用反射。数组类没有属性Count。它有一个属性Length,它明确地实现了ICollection属性Count。这意味着当您尝试执行动态调用时,它会失败,因为它无法找到匹配的属性。
我的问题是你为什么在这种情况下尝试使用动态 - 你已经将它限制为支持接口的类,此时你应该使用接口(这将起作用)。在这一点上,你几乎可以保证能够获得一个枚举器和计数 - 没有别的。如果您需要更多,请考虑更好的界面。
答案 2 :(得分:0)
“我知道我的解决方案是什么,但我想知道为什么编译器有这种行为?”
对于你的问题,我知道编译器的行为是...... 编译器在编译时不处理动态类型变量,因为动态类型是在运行时处理的。这就是出现错误的原因。
如果您希望编译器处理这种情况,您可以将动态类型更改为 var 类型。
简而言之..动态类型变量不是编译器的责任。
答案 3 :(得分:0)
这是因为该属性的名称是不是 Count
,而是System.Collections.ICollection.get_Count
。
如果你跑
foreach (var item in typeof(int[]).GetMembers(BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance))
Console.WriteLine(item.Name);
你会回来的
...
System.Collections.ICollection.get_Count
...
这是因为界面是明确实现的。