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?
source to share
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.
source to share