获取在c#中转换为动态的数组的计数

时间:2013-10-20 04:43:09

标签: c#

考虑以下代码:

  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'

我知道我的解决方案是什么,但我想知道为什么编译器有这种行为?

4 个答案:

答案 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
...

这是因为界面是明确实现的。