[编辑:我的道歉......原来的问题措辞含糊不清,我没有得到我要找的答案]
对于从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>
?
答案 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;
}
如果传入多维数组或构造类型,启动无论如何都可能会变得复杂一些。尽管如此,这一切都在课堂上。