最近我在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...

我们刚刚在字符串列表中添加了一个整数。编译器这样做是为了保护类型安全。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top