简体   繁体   中英

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> . 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. It may also has been implemented other interfaces.

However, C# supports this cast in it's later versions. Please see http://msdn.microsoft.com/en-us/library/dd799517.aspx (Covariance and Contravariance in Generics)

您可以先转换为对象

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

An even simpler objection - imagine that instead of Foo , this was, say 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 . 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 .


My point in the comments re: value types. 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. If you want a List<IWorld> of these same values, each value has to be boxed before it's added to the list.

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.

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).

If it is .NET 4, it should work automatically due to CoVariance feature.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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