Allan Rempel
Allan Rempel

Reputation: 73

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.

Upvotes: 7

Views: 131

Answers (4)

Tilak
Tilak

Reputation: 30698

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.

Upvotes: 0

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239646

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.

Upvotes: 1

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236208

You can cast to object first

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

Upvotes: 1

Yasser Zamani
Yasser Zamani

Reputation: 2500

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)

Upvotes: 1

Related Questions