Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is List<int> not IEnumerable<ValueType>?

Tags:

c#

.net

[Edit: My apologies ... the original question wording was ambiguous and I was not getting the responses I am looking for]

For any class X that inherits from class Y, new List<X>() is IEnumerable<Y> is true. However, this doesn't hold for structs: new List<int>() is IEnumerable<ValueType> is false. My question is: Why?

Here is a sample program:

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");
        }

    }
}

Output:

System.Collections.Generic.List`1[ConsoleApplication1.Program+X] is a list of Ys

System.Collections.Generic.List`1[System.String] is a list of objects

System.Collections.Generic.List`1[ConsoleApplication1.Program+Z] is most likely a list of ValueTypes or a string

System.Collections.Generic.List`1[System.Int32] is most likely a list of ValueTypes or a string

blah is most likely a list of ValueTypes or a string

1 is not a list

So why is new List<int> not a IEnumerable<ValueType>?

like image 740
Rado Avatar asked Nov 15 '11 23:11

Rado


2 Answers

Covariance works only for reference types, not for value types. So a List<string> is assignable to an IEnumerable<object> because string is a reference type, but a List<int> is not assignable to an IEnumerable<ValueType>. See section 13.1.3.2 of the C# language specifications for details

like image 155
Thomas Levesque Avatar answered Oct 22 '22 15:10

Thomas Levesque


The type of iArr (and subsequently iArr[i]) is known; the compiler can tell you that your expressions will always return a given value because it knows the answer at compile time. There is nothing dynamic going on here.

What are you actually trying to accomplish here? Why would you test if an int derives from ValueType? Of course it does; it's an int! This would possibly make sense were generics involved (though you would likely just use a constraint), but not here.

like image 42
Ed S. Avatar answered Oct 22 '22 14:10

Ed S.