在C#中强制约束泛型类

时间:2012-12-21 10:00:50

标签: c# generics casting

很简单,为什么这段代码无法编译?

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实施IWorldFoo<T>的每个实例都应与Foo<IWorld>匹配。为什么不?有没有办法解决?我真的不想诉诸于泛型来实现这一点。

4 个答案:

答案 0 :(得分:1)

T : IWorld

意味着T已经实施了IWorld,并不意味着它只实现了IWorld,而且确实是IWorld。它也可能已经实现了其他接口。

但是,C#在其更高版本中支持此演员。请参阅http://msdn.microsoft.com/en-us/library/dd799517.aspx(泛型中的协方差和反演)

答案 1 :(得分:1)

您可以先转换为对象

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

答案 2 :(得分:1)

更简单的反对意见 - 想象一下,Foo代替List,而不是List<T>

List<IWorld>转换为IWorld后,我现在可以添加一些其他 T2实施对象(比如类型T)限制为仅包含Foo类型的对象的列表。这不应该是有效的。

回到你的T对象 - 如果它包含任何期望用IWorld类型的对象调用的方法,我现在可以用任何对象调用它们实现Foo - 即使(想象Foo的其他类型约束)该对象也不是List<T>的合格类型。


我在评论中的观点:价值类型。同样,如果我们用List<T>来讨论,这可能会更容易 - 对于值类型,List<IWorld>包含没有装箱的值类型。如果您想要{{1}}这些相同的值,则每个值必须装箱才能添加到列表中。

答案 3 :(得分:0)

以下

有什么问题
 Foo<IWorld> bar1 = new Foo<IWorld>(); 

你想要达到什么目的?

如果您需要传递IWorld个实例,则可以安全地传递T,但代码中并非如此。

编辑(根据评论)

要转换为Foo<Array of something>,您可以使用CastOfType,具体取决于您的要求(无论您是要抛弃还是忽略不兼容的匹配)。

如果它是.NET 4,它应该由于CoVariance功能而自动运行。