从IEnumerable< Object>转换到IEnumerable< string>
-
03-07-2019 - |
题
最近我在c#中发现了一个非常令人惊讶的行为。
我有一个方法,它将 IEnumerable< Object>
作为参数,我正在传递
IEnumerable< string>
但是不可能。
虽然在c#中,所有内容都可以向上转换为对象而不是为什么这是不可能的?
这让我很困惑。
请有人在这个问题上告诉我。
解决方案
对此的技术术语是泛型在C#3.0及更早版本中是不变的。从C#4.0开始,演员工作。
什么是不变量意味着两个泛型类型之间没有关系,因为它们的泛型类型参数是相关的(即彼此的子类型或超类型)。
在您的示例中, IEnumerable< object>
与 IEnumerable< string>
之间没有类型关系,因为string是object的子类型。它们只被认为是两个完全不相关的类型,比如字符串和int(它们仍然是对象的子类型,但一切都是)
您遇到此问题有一些变通方法和例外。
首先,您可以将每个字符串单独转换为对象,如果您使用的是.NET 3.0,则可以使用 Cast< T>()
扩展方法执行此操作。否则,您可以使用foreach并将结果放入所需静态类型的新变量中。
其次,数组是引用类型的一个例外,即将string []类型传递给接受object []类型的方法应该有效。
其他提示
正如其他人所指出的那样,泛型类型是不变的。 IEnumerable< T>
可以是共变体,但C#目前不支持指定变体。预计C#4.0将支持变体,因此将来可能会支持这种变体。
要解决此问题,您现在可以使用LINQ扩展方法 Cast< object>()
。假设您有一个名为 Foo
的方法,该方法采用 IEnumerable< object>>
。你可以这样称呼它,
Foo(stringEnumerable.Cast<object>());
将 IEnumerable&lt; string&gt;
传递给需要 IEnumerable&lt; object&gt;
的函数的最简单方法是通过转换函数,如下所示:
public IEnumerable<object> convert<T>(IEnumerable<T> enumerable)
{
foreach (T o in enumerable)
yield return o;
}
当C#4出现时,这不是必要的,因为它将支持协方差和逆变。
您应该使用
IEnumerable<T>
如果你想传递不同的类型,那么你可以查询T以找出它是什么类型。
考虑这个问题的一个好方法是问问自己“如果你能做到这一点会怎么样?”。请看以下示例:
IEnumerable<String> strings=...;
IEnumerable<Object> objects = strings; // assume this were legal
objects.Add(new Integer(5)); // what the...
我们刚刚在字符串列表中添加了一个整数。编译器这样做是为了保护类型安全。