为什么List <int>不是IEnumerable <valuetype>?</valuetype> </int>

时间:2011-11-15 23:10:07

标签: c# .net

[编辑:我的道歉......原来的问题措辞含糊不清,我没有得到我要找的答案]

对于从Y类继承的任何类X,new List<X>() is IEnumerable<Y>为真。但是,这不适用于结构:new List<int>() is IEnumerable<ValueType>是错误的。我的问题是:为什么?

以下是一个示例程序:

class Program
{
    class Y { }
    class X : Y { }
    struct Z { }

    static void Main(string[] args)
    {
        Test(new List<X>());
        Test(new List<string>());
        Test(new List<Z>());
        Test(new List<int>());
        Test("blah");
        Test(1);
        Console.ReadLine();
    }

    static void Test(object o)
    {
        if (o is IEnumerable<Y>)
        {
            Console.WriteLine(o + " is a list of Ys");
        }
        else if (o is IEnumerable<ValueType>)
        {
            Console.WriteLine(o + " is a list of ValueTypes");
        }
        else if (o is IEnumerable<object>)
        {
            Console.WriteLine(o + " is a list of objects");
        }
        else if (o is System.Collections.IEnumerable)
        {
            Console.WriteLine(o + " is most likely a list of ValueTypes or a string");
        }
        else
        {
            Console.WriteLine(o + " is not a list");
        }

    }
}

输出:

  

System.Collections.Generic.List`1 [ConsoleApplication1.Program + X]是Y的列表

     

System.Collections.Generic.List`1 [System.String]是一个对象列表

     

System.Collections.Generic.List`1 [ConsoleApplication1.Program + Z]很可能是ValueTypes或字符串列表

     

System.Collections.Generic.List`1 [System.Int32]很可能是ValueTypes或字符串列表

     

blah很可能是ValueTypes列表或字符串

     

1不是列表

那么为什么new List<int>不是IEnumerable<ValueType>

6 个答案:

答案 0 :(得分:7)

协方差仅适用于引用类型,不适用于值类型。因此,List<string>可分配给IEnumerable<object>,因为string是引用类型,但List<int>不能分配给IEnumerable<ValueType>。有关详细信息,请参阅C#语言规范的第13.1.3.2节

答案 1 :(得分:1)

iArr(以及随后的iArr[i])的类型已知;编译器可以告诉您表达式将始终返回给定值,因为它在编译时知道答案。这里没有任何动态。

你到底想要在这里完成什么?为什么要测试int是否来自ValueType?当然可以;这是一个int!这可能是有意义的涉及泛型(虽然你可能只是使用约束),但不是在这里。

答案 2 :(得分:1)

在您的评论中,如果x派生自y,您希望List<x>List<y>派生,因此您希望某些检查为真。这是List<T>的无效假设。

如果类型x与类型y相关,则无法RandomGeneric<x>RandomGeneric<y>之间的关系进行任何说明而不查看类型themselvs。

在您的特定情况下,List<x>List<y>始终是兄弟类型(源自普通父母,但彼此之间没有关系)。 IEnumerable<x>IEnumerable<y>也是如此。

答案 3 :(得分:0)

问题没有意义iArr在其中有值类型,因为它是一个int数组。在编译时你唯一不知道元素类型的是你有一个对象的集合。在这种情况下,每个元素都可以是一个不同类型的元素,因此你必须检查每个元素。

e.g。

IEnumerable arse = SomeMethodThatReturnsIEnumerable();    
bool areAllValueTypes = arse.<OfTypeobject>().All(x => x is ValueType);

答案 4 :(得分:0)

这取决于你的意思。

var lst = new List<Object>();
lst.Add(1);
lst.Add(3);

这是碰巧只包含ValueTypes的对象集合。 这应该是真还是假? 如果它应该返回false,请使用:

private bool attemptOne(IEnumerable coll)
{
    var s = coll.GetType().GetGenericArguments()[0];
    return s.IsValueType;
}

var lstTwo = new List<int>();
lstTwo.Add(1);
lstTwo.Add(3);
Console.WriteLine(attemptOne(lstTwo)); // Returns true

如果它应该返回true,请使用:

private bool attemptTwo<T>(IEnumerable<T> coll)
{
    return coll.All(c => c.GetType().IsValueType);
}

请注意,对于非常大的集合,第二种方式需要很长时间。

答案 5 :(得分:0)

我想我能看到你得到的东西

bool IsCollectionOfValueTypes(Object argValue)
{
  Type t = argValue.GetType();
  if(t.IsArray)
  {
    return t.GetElementType().IsValueType;
  }
  else
  {
    if (t.IsGeneric)
    {
      Types[] gt = t.GetGenericArguments();
       return (gt.Length == 1) && gt[0].IsValueType;
    }
  }
  return false;
}

如果传入多维数组或构造类型,启动无论如何都可能会变得复杂一些。尽管如此,这一切都在课堂上。