Home > Net >  Casting of generic type does not compile
Casting of generic type does not compile

Time:04-02

Please have a look at the following code. Why do I get a compile-error?

I don't get it!

Casting is a way of telling the compiler that I know more about the objects than it does. And in this case, I know for fact, that "x" does actually contain an instance of "SomeClass". But the compiler seems to be unwilling to accept that information.

https://dotnetfiddle.net/0DlmXf

public class StrangeConversion 
{
    public class SomeClass { }
    public interface ISomeInterface { }
    public class Implementation : SomeClass, ISomeInterface { }
    public void Foo<T>() where T : class 
    {
        T x = (T)Factory();
        //Compile-error: Cannot convert type 'T' to 'SomeClass'
        SomeClass a = (SomeClass)x;
        //This is perfectly fine:
        SomeClass b = (SomeClass)(object)x;

        if (x is SomeClass c) 
        {
            //This works as well and 'c' contains the reference.
        }
    }
    private object Factory() 
    {
        return new Implementation();
    }
}

Edit: @Charles Mager has the correct answer in the comment: There does not seem to be a valid reason. The language designers just didn't want to allow this cast.

CodePudding user response:

I fixed using the as casting e.g.

SomeClass a = x as SomeClass;

This Answer explains is very well https://stackoverflow.com/a/132467/16690008

Essentially it's because it would throw an exception if T is not type of that class

CodePudding user response:

It's hard to make sense of exactly what you're trying to achieve, but it seems like a generic constraint is what you're after

public void Foo<T>()
    where T : SomeClass // constrain T to be inheriting from SomeClass
{
    T x = Factory<T>(); // x is guaranted to be SomeClass
}

private T Factory<T>()
    where T : SomeClass // same here
{
    return new Implementation();
}

CodePudding user response:

You constrain the generic to only reference types by specifying where T : class, but the compiler needs to know with certainty if the cast is possible. This means you are asking the compiler to trust that SomeClass can be cast from any reference type you pass to it, which is something it won't do. The microsoft docs state that for the class generic type constraint:

The type argument must be a reference type. This constraint applies also to any class, interface, delegate, or array type.

Its important to note that SomeClass b = (SomeClass)(object)x; works because of the cast to object which is the root of the object hierarchy. But as you can see from the list of supported reference types, SomeClass a = (SomeClass)x; has to account for things such as delegates, array types, etc., at which point the compiler will throw you the error

Don't do SomeClass b = (SomeClass)(object)x;, it is much cleaner to make proper use of type constraints along with the as & is operators which were designed for this exact purpose of type checking and safe casting

  • Related