简体   繁体   English

在C#中强制约束泛型类

[英]Casting constrained generic class in C#

Quite simply, why does this code fail to compile? 很简单,为什么这段代码无法编译?

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
}

Since every T implements IWorld , every instance of Foo<T> should match Foo<IWorld> . 由于每个T实现了IWorld ,因此Foo<T>每个实例都应该与Foo<IWorld>匹配。 Why not? 为什么不? Is there any way around this? 有没有办法解决? I really don't want to resort to generics to accomplish this. 我真的不想借助于泛型来实现这一目标。

T : IWorld

means that T has been implemented IWorld and does not mean that it ONLY has implemented IWorld and EXACTLY is IWorld. 意味着T已经实施了IWorld,并不意味着它只实现了IWorld,而且确实是IWorld。 It may also has been implemented other interfaces. 它也可能已经实现了其他接口。

However, C# supports this cast in it's later versions. 但是,C#在其更高版本中支持此演员。 Please see http://msdn.microsoft.com/en-us/library/dd799517.aspx (Covariance and Contravariance in Generics) 请参阅http://msdn.microsoft.com/en-us/library/dd799517.aspx (泛型中的协方差和反演)

您可以先转换为对象

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

An even simpler objection - imagine that instead of Foo , this was, say List . 一个更简单的反对意见 - 想象一下,而不是Foo ,这就是List

Having converted your List<T> to a List<IWorld> , I can now add some other IWorld implementing object (say of type T2 ) to a list that is constrained to only contain objects of type T . List<T>转换为List<IWorld> ,我现在可以将一些其他 IWorld实现对象(比如T2类型)添加到一个列表中,该列表仅限于包含T类型的对象。 That shouldn't be valid. 这不应该是有效的。

So back to your Foo object - if it contains any methods that expect to be called with objects of type T , I can now call them with any object that implements IWorld - even if (imagine an additional type constraint of Foo ) that object would not be an eligible type for Foo . 所以回到你的Foo对象 - 如果它包含任何期望用类型T对象调用的方法,我现在可以用任何实现IWorld对象来调用它们 - 即使(想象一下Foo的另一个类型约束)该对象也不会是Foo的合格类型。


My point in the comments re: value types. 我在评论中的观点re:值类型。 Again, this may be easier if we talk in terms of List<T> - a List<T> for value types contains the value types without boxing. 同样,如果我们按照List<T>讨论,这可能会更容易 - 值类型的List<T>包含没有装箱的值类型。 If you want a List<IWorld> of these same values, each value has to be boxed before it's added to the list. 如果您需要具有这些相同值的List<IWorld> ,则必须在将每个值添加到列表之前将其装箱

What is the problem with following 以下是什么问题

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

What are you trying to achieve? 你想要实现什么目标?

If you need to pass IWorld instance, you can safely pass T , but that is not the case in your code. 如果你需要传递IWorld实例,你可以安全地传递T ,但在你的代码中并非如此。

EDIT (Based on comments) 编辑 (根据评论)

To cast to Foo<Array of something> you can use Cast or OfType depending on your requirement(whether you want to throw or ignore incompatible matches). 要转换为Foo<Array of something>您可以根据您的要求使用CastOfType (无论您是要抛出还是忽略不兼容的匹配)。

If it is .NET 4, it should work automatically due to CoVariance feature. 如果它是.NET 4,它应该由于CoVariance功能自动工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM