最近我在C#中发现了一个非常令人惊讶的行为。
我有一个方法,它以IEnumerable<Object>
作为参数,我传递了IEnumerable<string>
,但这是不可能的。
在C#中,所有东西都可以向上转换为Object,那么为什么这不可能呢?
这对我来说完全令人困惑。
请有人帮我解决这个问题。
最近我在C#中发现了一个非常令人惊讶的行为。
我有一个方法,它以IEnumerable<Object>
作为参数,我传递了IEnumerable<string>
,但这是不可能的。
在C#中,所有东西都可以向上转换为Object,那么为什么这不可能呢?
这对我来说完全令人困惑。
请有人帮我解决这个问题。
技术术语是,C# 3.0及更早版本的泛型是不变的。C# 4.0及以后版本,强制转换有效。
"不变"指的是两个泛型类型之间没有关系,即使它们的泛型参数相关 (即彼此为子类或超类)。
在您的示例中,一个 IEnumerable<object>
和一个 IEnumerable<string>
之间没有类型关系,仅因为 string 是 object 的子类型。它们被认为是两个完全无关的类型,就像字符串和整数一样(它们仍然都是 object 的子类型,但这没什么用)。
对于您遇到的问题,有一些解决方法和例外情况。
首先,如果您使用 .NET 3.0,您可以使用 Cast<T>()
扩展方法将每个字符串单独转换为对象。否则,您可以使用 foreach 并将结果放入要使用的静态类型的新变量中。
其次,数组是引用类型的例外情况,即向接受 object[] 类型的方法传递 string[] 类型应该可行。
Foo(stringEnumerable.Cast<object>());
public IEnumerable<object> convert<T>(IEnumerable<T> enumerable)
{
foreach (T o in enumerable)
yield return o;
}
你应该使用
IEnumerable<T>
IEnumerable<String> strings=...;
IEnumerable<Object> objects = strings; // assume this were legal
objects.Add(new Integer(5)); // what the...
IEnumerable<T>
变成了 IEnumerable<out T>
,这是因为你的论点对于容器来说是有道理的,但对于枚举来说则不然。 - Sam Harwell