在C#中转换受限制的泛型类

7
很简单,为什么这段代码无法编译?
public interface IWorld { }
public class Foo<T> where T : IWorld { }
public void Hello<T>(T t) where T : IWorld
{
    Foo<IWorld> bar1 = new Foo<T>(); //fails implicit cast
    Foo<IWorld> bar2 = (Foo<IWorld>)new Foo<T>(); //fails explicit cast
}

由于每个 T 都实现了 IWorld,所以每个 Foo<T> 的实例都应该匹配 Foo<IWorld>。为什么不行呢?有没有什么解决方法?我真的不想使用泛型来完成这个任务。


值类型可以实现接口。每个值类型都会获得其自己的泛型代码实现。一个 Foo<IWorld> 将使用引用类型实现。因此,存在类型不匹配的问题。 - Damien_The_Unbeliever
即使T是一个实现接口的值类型,Foo<T>仍然是一个类,因此是引用类型。 - Allan Rempel
4个回答

1

你可以先转换为对象

Foo<IWorld> bar2 = (Foo<IWorld>)(object)new Foo<T>();

1
T : IWorld

这意味着T已经在IWorld中实现,但并不意味着它仅仅实现了IWorld接口或者确切地说是IWorld接口。它也可能已经实现了其他接口。

然而,在C#的后续版本中支持此转换。请参见http://msdn.microsoft.com/en-us/library/dd799517.aspx(泛型中的协变和逆变)。


它支持接口和委托的协变性\逆变性实际上是吗? - horgh
谢谢,我之前不知道协变和逆变。 - Allan Rempel

1

一个更简单的反对意见——想象一下,如果这不是 Foo,而是 List

将你的 List<T> 转换为 List<IWorld> 后,我现在可以向只包含类型为 T 的对象的列表中添加一些其他实现 IWorld 接口的对象(例如 T2 类型)。 这不应该被认为是有效的。

所以回到你的 Foo 对象——如果它包含任何期望以 T 类型的对象调用的方法,我现在可以使用任何实现 IWorld 的对象来调用它们——即使(想象一下 Foo 的附加类型约束)那个对象不是 Foo 的可选类型。


关于值类型的评论,我的观点是:如果我们用 List<T> 来讨论,这可能会更容易理解 - 对于值类型的 List<T> 包含不需要装箱的值类型。如果你想要一个包含相同值的 List<IWorld>,每个值都必须在添加到列表之前进行装箱


0

以下代码有什么问题?

 Foo<IWorld> bar1 = new Foo<IWorld>(); 

你想要达到什么目的?
如果你需要传递 IWorld 实例,你可以安全地传递 T,但是在你的代码中并非如此。
编辑(基于评论)

如果要将类型转换为 Foo<某些数组>,您可以使用 CastOfType,具体取决于您的要求(是否希望抛出或忽略不兼容的匹配项)。

如果是.NET 4,由于协变特性,它应该可以自动工作。


Foo是一个包装器,可以包装任何泛型数组。我想让这个Foo实例包装一个T[]数组,而不是基本的IWorld[]数组。 - Allan Rempel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接