从 IEnumerable进行转换 到 IEnumerable;

发布于 2024-07-14 15:45:00 字数 205 浏览 7 评论 0原文

最近我在 C# 中发现了一个非常令人惊讶的行为。 我有一个方法,它将 IEnumerable作为参数,并且我正在传递 IEnumerable 但这是不可能的。 虽然在 C# 中,所有内容都可以向上转型为 Object,但为什么这是不可能的? 这对我来说完全令人困惑。 请有人澄清我这个问题。

Recently I found a very surprising behavior in c#.
I had a method which takes IEnumerable<Object> as a parameter and i was passing
IEnumerable<string> but it's not possible.
While in c# everything can be upcast to Object than why this is not possible?
It's totally confusing for me.
Please someone clear me on this issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

叫思念不要吵 2024-07-21 15:45:00

其技术术语是泛型在 C# 3.0 及更早版本中是不变的。 从 C#4.0 开始,强制转换就起作用了。

不变意味着两个泛型类型之间不存在任何关系,仅仅因为它们的泛型类型参数相关(即彼此是子类型或超类型)。

在您的示例中, IEnumerableIEnumerable 之间没有类型关系,只是因为 string 是对象的子类型。 它们只是被认为是两种完全不相关的类型,例如字符串和整数(它们仍然都是对象的子类型,但一切都是)

对于您遇到的这个问题,有一些解决方法和例外。

首先,您可以将每个字符串单独转换为对象,如果您使用的是 .NET 3.0,则可以使用 Cast() 扩展方法来执行此操作。 否则,您可以使用 foreach 并将结果放入所需静态类型的新变量中。

其次,数组是引用类型的一个例外,即将 string[] 类型传递给接受 object[] 类型的方法应该可以工作。

The technical term for this is that generics are invariant in C# 3.0 and earlier. From C#4.0 onward, the cast works.

What invariant means is that there is no relationship between two generic types just because their generic type parameters are related (i.e. are sub- or supertypes of each other).

In your example, there is no typing relationship between an IEnumerable<object> and an IEnumerable<string>, just because string is a subtype of object. They're just considered two completely unrelated types, like a string and an int (they still both are subtypes of object, but everything is)

There are a few workarounds and exceptions for this issue you've run into.

First, you can cast each string individually to object, if you're using .NET 3.0 you can do that using the Cast<T>() extension method. Otherwise, you can use a foreach and put the result into a new variable of the static type you want.

Second, arrays are an exception for reference type, i.e. passing in a string[] type to a method acccepting object[] types should work.

相思故 2024-07-21 15:45:00

正如其他人指出的那样,泛型类型是不变的。 IEnumerable 可以是协变体,但 C# 目前不支持指定变体。 C# 4.0 预计将支持变体,因此将来可能会得到支持。

现在要解决此问题,您可以使用 LINQ 扩展方法 Cast()。 假设您有一个名为 Foo 的方法,该方法采用 IEnumerable>。 你可以这样称呼它,

Foo(stringEnumerable.Cast<object>());

As others have pointed out, generics types are invariant. IEnumerable<T> could be co-variant but C# doesn't currently support specifying variants. C# 4.0 is expected to support variants so this might be supported in the future.

To work around this now you can using a the LINQ extension method Cast<object>(). Assuming you have a method called Foo that takes an IEnumerable<object>>. You can call it like this,

Foo(stringEnumerable.Cast<object>());
浅黛梨妆こ 2024-07-21 15:45:00

IEnumerable 传递给需要 IEnumerable的函数的最简单方法是通过如下转换函数:

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable)
    {
    foreach (T o in enumerable)
        yield return o;
    }

当 C# 4 出现时,这将不再是必需的,因为它将支持协变和逆变。

The easiest way to pass IEnumerable<string> to function requiring IEnumerable<object> is through converting function like this:

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable)
    {
    foreach (T o in enumerable)
        yield return o;
    }

When C# 4 comes out, this won't be neccessary, because it will support covariance and contravariance.

囚你心 2024-07-21 15:45:00

如果你想传递不同的类型,你应该使用

IEnumerable<T> 

,然后你可以查询 T 来找出它是什么类型。

You should be using

IEnumerable<T> 

if you want to pass in different types, then you can query T to find out what type it is.

岛徒 2024-07-21 15:45:00

思考这个问题的一个好方法是问自己“如果你能做到这一点会发生什么?”。 举个例子:

IEnumerable<String> strings=...;
IEnumerable<Object> objects = strings; // assume this were legal

objects.Add(new Integer(5)); // what the...

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

A good way to think about this is to ask yourself "What would happen if you could do this?". Take the following example:

IEnumerable<String> strings=...;
IEnumerable<Object> objects = strings; // assume this were legal

objects.Add(new Integer(5)); // what the...

We just added an integer to a list of strings. The compiler does this to preserve type safety.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文