Explicit casting versus using "as" within a generic method

I have a simple interface and two classes implement it:

public interface IMovable { }

public class Human : IMovable { }
public class Animal : IMovable { }

      

The following general method results in a compile-time error: Cannot convert type 'Human' to 'T'

public static T DoSomething<T>(string typeCode) where T : class, IMovable
{
    if (typeCode == "HUM")
    {
        return (T)new Human();      // Explicit cast
    }
    else if (typeCode == "ANI")
    {
        return (T)new Animal();     // Explicit cast
    }
    else
    {
        return null;
    }
}

      

But when the keyword is used as

everything is fine:

public static T DoSomething<T>(string typeCode) where T : class, IMovable
{
    if (typeCode == "HUM")
    {
        return new Human() as T;     // 'as'
    }
    else if (typeCode == "ANI")
    {
        return new Animal() as T;    // 'as'
    }
    else
    {
        return null;
    }
}

      

Why does it work as

but is not explicitly used?

+3


source to share


3 answers


With your code you can call the phone DoSomething<Animal>

and then you have (Animal)new Human()

.
It's biologically correct, but your model doesn't allow it.



Do you really need generics? Perhaps you just want to return IMovable

in this case.

+5


source


Short answer, because it T

doesn't have to be the type you want. The compiler is really trying to help you here because you are doing something that can easily fail at runtime.

eg. consider what's going on with:

var result = DoSomething<Human>("ANI");

      

Longer answer: you shouldn't quit at all. Casting points out problems with your OOP design and is especially flawed when using generics: in fact, you are missing out on the totality of generics. Generics are supposed to allow you to create a "template" that abstracts the actual type, leaving you to worry about the algorithm itself instead of the specific types.

In this case, you probably don't need generics at all. Your method is basically the less secure way to do it:

public static T DoSomething<T>() where T : new()
{
    return new T();
}

      

or that:



public static IMovable DoSomething(string typeCode)
{
    if (typeCode == "HUM")
        return new Human();

    if (typeCode == "ANI")
        return new Animal();

    return null;
}

      

To silence the compiler, you can also add an intermediate share that tells the compiler that you have taken an extra step to indicate that you really want to use it this way: for example, using

(T)(object)new Human()

      

or

(T)(IMovable)new Human() 

      

both will commit compilation, although converting from IMovable

to is T

not safer than source code and distinguishes object

to T

even incompatible. But this is not a solution to your main design problem.

+5


source


Under the covers the "how" will check the "is" before attempting to shoot. So it will not try to execute it if it cannot use it, and then it will return null.

+1


source







All Articles