I'm running into troubles with C# generics:
MappingAdapter is a common abstract base class that FullMappingAdapter and LiteMappingAdapter inherit from / implement.
Creating an instance of my generic class session:
session = new Session<FullMappingAdapter>(
// ...
)
In session, deciding what kind of session we are:
// class declaration:
public class Session<T> : ISession
where T : MappingAdapter {
// ...
// method body:
T t = null;
if (t is FullMappingAdapter) {
// need parameter, cannot use where T : new() above
t = new FullMappingAdapter(someData) as T;
} else if (t is LiteMappingAdapter) {
t = new LiteMappingAdapter(someData) as T;
} else {
throw new NotSupportedException("Unknown Adapter specified, please fix.");
}
// ... more methods here ...
}
I always get NotSupportedException thrown. Also, when looking at my stack in the debugger it says "FullMappingAdapter" in the "type" column of t, which is correct, and what I expected. But why doesn't the "is" keyword also recognize the type?
What am I doing wrong?
null is never anything.
You want to check typeof(T) for being exact type (or maybe IsAssignableFrom) instead.
Exact match (not the same as is FullMappingAdapter because it will not include derived types)
if(typeof(T) == typeof(FullMappingAdapter))
Assignable - same as is FullMappingAdapter:
if (typeof(FullMappingAdapter).IsAssignableFrom(typeof(T))
You should modify your check to use typeof:
if (typeof(T) == typeof(FullMappingAdapter))
and so on
You have to check like this
if (typeof(T) == typeof(FullMappingAdapter))
Related
I've seen many people use the following code:
Type t = obj1.GetType();
if (t == typeof(int))
// Some code here
But I know you could also do this:
if (obj1.GetType() == typeof(int))
// Some code here
Or this:
if (obj1 is int)
// Some code here
Personally, I feel the last one is the cleanest, but is there something I'm missing? Which one is the best to use, or is it personal preference?
All are different.
typeof takes a type name (which you specify at compile time).
GetType gets the runtime type of an instance.
is returns true if an instance is in the inheritance tree.
Example
class Animal { }
class Dog : Animal { }
void PrintTypes(Animal a) {
Console.WriteLine(a.GetType() == typeof(Animal)); // false
Console.WriteLine(a is Animal); // true
Console.WriteLine(a.GetType() == typeof(Dog)); // true
Console.WriteLine(a is Dog); // true
}
Dog spot = new Dog();
PrintTypes(spot);
What about typeof(T)? Is it also resolved at compile time?
Yes. T is always what the type of the expression is. Remember, a generic method is basically a whole bunch of methods with the appropriate type. Example:
string Foo<T>(T parameter) { return typeof(T).Name; }
Animal probably_a_dog = new Dog();
Dog definitely_a_dog = new Dog();
Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.
Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal".
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
Use typeof when you want to get the type at compilation time. Use GetType when you want to get the type at execution time. There are rarely any cases to use is as it does a cast and, in most cases, you end up casting the variable anyway.
There is a fourth option that you haven't considered (especially if you are going to cast an object to the type you find as well); that is to use as.
Foo foo = obj as Foo;
if (foo != null)
// your code here
This only uses one cast whereas this approach:
if (obj is Foo)
Foo foo = (Foo)obj;
requires two.
Update (Jan 2020):
As of C# 7+, you can now cast inline, so the 'is' approach can now be done in one cast as well.
Example:
if(obj is Foo newLocalFoo)
{
// For example, you can now reference 'newLocalFoo' in this local scope
Console.WriteLine(newLocalFoo);
}
1.
Type t = typeof(obj1);
if (t == typeof(int))
This is illegal, because typeof only works on types, not on variables. I assume obj1 is a variable. So, in this way typeof is static, and does its work at compile time instead of runtime.
2.
if (obj1.GetType() == typeof(int))
This is true if obj1 is exactly of type int. If obj1 derives from int, the if condition will be false.
3.
if (obj1 is int)
This is true if obj1 is an int, or if it derives from a class called int, or if it implements an interface called int.
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
This is an error. The typeof operator in C# can only take type names, not objects.
if (obj1.GetType() == typeof(int))
// Some code here
This will work, but maybe not as you would expect. For value types, as you've shown here, it's acceptable, but for reference types, it would only return true if the type was the exact same type, not something else in the inheritance hierarchy. For instance:
class Animal{}
class Dog : Animal{}
static void Foo(){
object o = new Dog();
if(o.GetType() == typeof(Animal))
Console.WriteLine("o is an animal");
Console.WriteLine("o is something else");
}
This would print "o is something else", because the type of o is Dog, not Animal. You can make this work, however, if you use the IsAssignableFrom method of the Type class.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
This technique still leaves a major problem, though. If your variable is null, the call to GetType() will throw a NullReferenceException. So to make it work correctly, you'd do:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
With this, you have equivalent behavior of the is keyword. Hence, if this is the behavior you want, you should use the is keyword, which is more readable and more efficient.
if(o is Animal)
Console.WriteLine("o is an animal");
In most cases, though, the is keyword still isn't what you really want, because it's usually not enough just to know that an object is of a certain type. Usually, you want to actually use that object as an instance of that type, which requires casting it too. And so you may find yourself writing code like this:
if(o is Animal)
((Animal)o).Speak();
But that makes the CLR check the object's type up to two times. It will check it once to satisfy the is operator, and if o is indeed an Animal, we make it check again to validate the cast.
It's more efficient to do this instead:
Animal a = o as Animal;
if(a != null)
a.Speak();
The as operator is a cast that won't throw an exception if it fails, instead returning null. This way, the CLR checks the object's type just once, and after that, we just need to do a null check, which is more efficient.
But beware: many people fall into a trap with as. Because it doesn't throw exceptions, some people think of it as a "safe" cast, and they use it exclusively, shunning regular casts. This leads to errors like this:
(o as Animal).Speak();
In this case, the developer is clearly assuming that o will always be an Animal, and as long as their assumption is correct, everything works fine. But if they're wrong, then what they end up with here is a NullReferenceException. With a regular cast, they would have gotten an InvalidCastException instead, which would have more correctly identified the problem.
Sometimes, this bug can be hard to find:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
This is another case where the developer is clearly expecting o to be an Animal every time, but this isn't obvious in the constructor, where the as cast is used. It's not obvious until you get to the Interact method, where the animal field is expected to be positively assigned. In this case, not only do you end up with a misleading exception, but it isn't thrown until potentially much later than when the actual error occurred.
In summary:
If you only need to know whether or not an object is of some type, use is.
If you need to treat an object as an instance of a certain type, but you don't know for sure that the object will be of that type, use as and check for null.
If you need to treat an object as an instance of a certain type, and the object is supposed to be of that type, use a regular cast.
If you're using C# 7, then it is time for an update to Andrew Hare's great answer. Pattern matching has introduced a nice shortcut that gives us a typed variable within the context of the if statement, without requiring a separate declaration/cast and check:
if (obj1 is int integerValue)
{
integerValue++;
}
This looks pretty underwhelming for a single cast like this, but really shines when you have many possible types coming into your routine. The below is the old way to avoid casting twice:
Button button = obj1 as Button;
if (button != null)
{
// do stuff...
return;
}
TextBox text = obj1 as TextBox;
if (text != null)
{
// do stuff...
return;
}
Label label = obj1 as Label;
if (label != null)
{
// do stuff...
return;
}
// ... and so on
Working around shrinking this code as much as possible, as well as avoiding duplicate casts of the same object has always bothered me. The above is nicely compressed with pattern matching to the following:
switch (obj1)
{
case Button button:
// do stuff...
break;
case TextBox text:
// do stuff...
break;
case Label label:
// do stuff...
break;
// and so on...
}
EDIT: Updated the longer new method to use a switch as per Palec's comment.
I had a Type-property to compare to and could not use is (like my_type is _BaseTypetoLookFor), but I could use these:
base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);
Notice that IsInstanceOfType and IsAssignableFrom return true when comparing the same types, where IsSubClassOf will return false. And IsSubclassOf does not work on interfaces, where the other two do. (See also this question and answer.)
public class Animal {}
public interface ITrainable {}
public class Dog : Animal, ITrainable{}
Animal dog = new Dog();
typeof(Animal).IsInstanceOfType(dog); // true
typeof(Dog).IsInstanceOfType(dog); // true
typeof(ITrainable).IsInstanceOfType(dog); // true
typeof(Animal).IsAssignableFrom(dog.GetType()); // true
typeof(Dog).IsAssignableFrom(dog.GetType()); // true
typeof(ITrainable).IsAssignableFrom(dog.GetType()); // true
dog.GetType().IsSubclassOf(typeof(Animal)); // true
dog.GetType().IsSubclassOf(typeof(Dog)); // false
dog.GetType().IsSubclassOf(typeof(ITrainable)); // false
I prefer is
That said, if you're using is, you're likely not using inheritance properly.
Assume that Person : Entity, and that Animal : Entity. Feed is a virtual method in Entity (to make Neil happy)
class Person
{
// A Person should be able to Feed
// another Entity, but they way he feeds
// each is different
public override void Feed( Entity e )
{
if( e is Person )
{
// feed me
}
else if( e is Animal )
{
// ruff
}
}
}
Rather
class Person
{
public override void Feed( Person p )
{
// feed the person
}
public override void Feed( Animal a )
{
// feed the animal
}
}
I believe the last one also looks at inheritance (e.g. Dog is Animal == true), which is better in most cases.
It depends on what I'm doing. If I need a bool value (say, to determine if I'll cast to an int), I'll use is. If I actually need the type for some reason (say, to pass to some other method) I'll use GetType().
The last one is cleaner, more obvious, and also checks for subtypes. The others do not check for polymorphism.
Used to obtain the System.Type object for a type. A typeof expression takes the following form:
System.Type type = typeof(int);
Example:
public class ExampleClass
{
public int sampleMember;
public void SampleMethod() {}
static void Main()
{
Type t = typeof(ExampleClass);
// Alternatively, you could use
// ExampleClass obj = new ExampleClass();
// Type t = obj.GetType();
Console.WriteLine("Methods:");
System.Reflection.MethodInfo[] methodInfo = t.GetMethods();
foreach (System.Reflection.MethodInfo mInfo in methodInfo)
Console.WriteLine(mInfo.ToString());
Console.WriteLine("Members:");
System.Reflection.MemberInfo[] memberInfo = t.GetMembers();
foreach (System.Reflection.MemberInfo mInfo in memberInfo)
Console.WriteLine(mInfo.ToString());
}
}
/*
Output:
Methods:
Void SampleMethod()
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Members:
Void SampleMethod()
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Void .ctor()
Int32 sampleMember
*/
This sample uses the GetType method to determine the type that is used to contain the result of a numeric calculation. This depends on the storage requirements of the resulting number.
class GetTypeTest
{
static void Main()
{
int radius = 3;
Console.WriteLine("Area = {0}", radius * radius * Math.PI);
Console.WriteLine("The type is {0}",
(radius * radius * Math.PI).GetType()
);
}
}
/*
Output:
Area = 28.2743338823081
The type is System.Double
*/
I found checking if the type of something is equal to something is done by the following:
variableName.GetType() == typeof(int)
if (c is UserControl) c.Enabled = enable;
You can use "typeof()" operator in C# but you need to call the namespace using System.IO; You must use "is" keyword if you wish to check for a type.
Performance test typeof() vs GetType():
using System;
namespace ConsoleApplication1
{
class Program
{
enum TestEnum { E1, E2, E3 }
static void Main(string[] args)
{
{
var start = DateTime.UtcNow;
for (var i = 0; i < 1000000000; i++)
Test1(TestEnum.E2);
Console.WriteLine(DateTime.UtcNow - start);
}
{
var start = DateTime.UtcNow;
for (var i = 0; i < 1000000000; i++)
Test2(TestEnum.E2);
Console.WriteLine(DateTime.UtcNow - start);
}
Console.ReadLine();
}
static Type Test1<T>(T value) => typeof(T);
static Type Test2(object value) => value.GetType();
}
}
Results in debug mode:
00:00:08.4096636
00:00:10.8570657
Results in release mode:
00:00:02.3799048
00:00:07.1797128
Suppose we have an interface with a single generic method:
public interface IExtender
{
T GetValue<T>(string tag);
}
and a simple implementation A of it that returns instances of two different types (B and C) depending on the "tag" parameter:
public class A : IExtender
{
public T GetValue<T>(string tag)
{
if (typeof(T) == typeof(B) && tag == null)
return (T)(object) new B();
if (typeof(T) == typeof(C) && tag == "foo")
return (T)(object) new C();
return default(T);
}
}
is it possible to avoid the double cast (T)(object)? Or, is there a way to tell the compiler "hey, I am sure that this cast won't fail at runtime, just let me do it without first casting to object!"
Or, is there a way to tell the compiler "hey, I am sure that this cast won't fail at runtime, just let me do it without first casting to object!"
No, the language is deliberately designed to prevent this. Eric Lippert blogged about this recently. I agree it's annoying, but it does make a certain kind of sense.
To be honest, "generic" methods like this are usually a bit of a design smell. If a method has to have special cases for various different types, you should at least consider using separate methods instead. (GetB, GetC)
public T MyMethod<T>(string tag) where T : class
{
return new A() as T;
}
check this sample:
public T GetValue<T>(string tag) where T : class, new()
{
if (typeof(T) == typeof(B) && tag == null)
return new T();
if (typeof(T) == typeof(C) && tag == "foo")
return new T();
return default(T);
}
no cast needed, you can create instance of "T", just add the generic constraint that saying that T is a class and it have parameterless constructor so you don't need to create another base types and you can be sure that only suitable types will go through this generic method.
You can use dynamic to store your real result, but you have to be sure the generic argument type is the right type you return.
TResult GetResult<TResult>()
{
dynamic r = 10;
return r;
}
No, that is not possible. The only way to do so would be to let the compiler know about additional assumptions on T. As evidenced by the list of generic parameter constraints, there is no constraint defined in C# to require availability of a specific cast.
if you let B and C implement the same interface you could use a type constraint on your T. Probably not exactly what you want, but as suggested also by others what you want is not really possible.
public interface IclassBndC {}
public class B : IclassBandC {}
public class C : IclassBandC {}
public class A : IExtender
{
public T GetValue<T>(string tag) where T : IclassBandC
{
if (tag == null)
return new B();
if (tag == "foo")
return new C();
return default(T);
}
}
I need to test if a value is an instance of a generic base class, without knowing the generic type parameter. Using the MSDN example as the base of my example, this is what I'd like to accomplish:
using System;
public class Class1<T> { }
public class DerivedC1 : Class1<int> { }
class IsSubclassTest
{
public static void Main()
{
Console.WriteLine(
"DerivedC1 subclass of Class1: {0}",
typeof(DerivedC1).IsSubclassOf(typeof(Class1<>)) // <- Here.
);
}
}
While this is syntactically correct, it always yields false. If I remove the generic type parameter, it works as expected (returns true).
How can I test if a class type is a subclass of a generic base class, without knowing its generic type parameter as such?
The problem is that DrevidedC1 is not a sublcass of Class1<T>, it's a subclass of Class1<int>. Make sure you understand this subtle diference; Class1<T> is a open type (T can be anything, it hasn't been set) while DerivedC1 extends a closed type Class1<int> (it's not open in T anymore, T is set to int and only int). So when you do the following:
typeof(DerivedC1).IsSubclassOf(typeof(Class1<>))
The answer is evidently false.
What you need to do is check if the generic type definition of DerivedC1's base type (think of it as the corresponding open generic type of Class1<int>) equals Class1<T> which it clearly does.
The correct code is therefore:
typeof(DerivedC1).BaseType.GetGenericTypeDefinition() == typeof(Class1<>));
Or better yet, as MatÃas Fidemraizer states in his answer:
typeof(DerivedC1).BaseType.GetGenericTypeDefinition().IsAssignableFrom(typeof(Class1<>)));
There's special methods on Type for this sort of thing. As far as I can see, you'll need to walk up your base-types and check each in turn until you either (a) hit a match or (b) get to the top of the inheritance hierarchy (i.e. System.Object).
As such, the following (recursive) extension method:
public static class TypeExtensions
{
public static bool IsDerivedFromGenericParent(this Type type, Type parentType)
{
if(!parentType.IsGenericType)
{
throw new ArgumentException("type must be generic", "parentType");
}
if(type == null || type == typeof(object))
{
return false;
}
if(type.IsGenericType && type.GetGenericTypeDefinition() == parentType)
{
return true;
}
return type.BaseType.IsDerivedFromGenericParent(parentType)
|| type.GetInterfaces().Any(t=>t.IsDerivedFromGenericParent(parentType));
}
}
will allow you to do the following
typeof(DerivedC1).IsDerivedFromGenericParent(typeof(Class1<>))
...and will also work if you test something derived from DerivedC1.
Changing typeof(DerivedC1).IsSubclassOf(typeof(Class1<>)) to typeof(Class1<>).IsAssignableFrom(typeof(DerivedC1).BaseType.GetGenericTypeDefinition()) should be enough in your case.
Type.IsAssignableFrom is more powerful than using Type.IsSubClassOf because it just checks if some type is assignable to other type. This includes, the same type, interface types and other cases.
public class BaseGenericType<T>
{
}
public class SubGenericType<T>: BaseGenericType<List<T>>
{
}
I have two generic types above, which one inherits from another but is still generic.
The strange thing I can't figure out is that typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>)) returns false. And typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>)) still returns false. I've tried GetGenericTypeDefinition() and MakeGenericType() and GetGenericArguments() to check the inheritance, still not working. But typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>)) returns true.
What I want is to get all classes by reflection then grab the specific class which inherits from a generic type passed in.
e.g.
(1)List<int> -->
(2)get generic type definition ==> List<T> -->
(3)make generic ==> BaseGenericType<List<T>> -->
(4)find subclass ==> SubGenericType<T>
(5)make generic ==> SubGenericType<int>
In step (4) I find nothing although I actually have that SubGenericType<T>. Why is that?
Once I wrote this method to check generic type inheritance:
static bool IsSubclassOfOpenGeneric(Type generic, Type toCheck)
{
while (toCheck != null && toCheck != typeof(object))
{
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur)
{
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
This returns true:
IsSubclassOfOpenGeneric(typeof(BaseGenericType<>), typeof(SubGenericType<int>))
It doesn't check interfaces though.
By the way, usually if you have relations like this, and you write all the classes yourself, consider using interfaces. It is much easier to handle. You can for instance have a IGenericType interface without generic argument. Sometome you just do not care about the generic type and just want to access members which do not depend on the generic type. Sometimes you want to simply check if it is one of those. And you can use type variance.
Finally, I figured it out.
This is the very solution. To explain in details, I have to introduce some non-abstract coding:
It's about a value converter. My purpose is simple, to let users add their own value converters. In the conversion step, I will check built-in types' converters first(as IConvertible), if not found, I'll first search the current executing assembly for all custom converter classes that inherit a specific abstract class provided by me. And an interface is implemented by that abstract class to make constraint for later reflection. Then I filter those reflected classes for the one that matches.
Here is the base class and interface(all nested):
private interface ICustomConverter
{
Type SourceType { get; }
object CallConvert(string input);
}
public abstract class CustomConverter<T> : ICustomConverter
{
public abstract T Convert(string input);
public Type SourceType
{
get { return typeof (T); }
}
object ICustomConverter.CallConvert(string input)
{
return Convert(input);
}
}
I've made the interface private in the parent class and implemented explicitly. So that the method CallConvert() won't be called outside.
The generic parameter T is the Type to convert the string value to.
e.g.
public class Int32Converter:CustomConverter<int>
{
}
This is easy to handle since the conversion target type isn't generic. all I need to do is to get all types that implement ICustomConverter, and make a generic type from CustomConverter<T> with the given int, thus CustomConverter<int>. Then I filter those classes for the one that derives from CustomConverter<int>, and here I found Int32Converter.
Later I came across this situation:
public class ListConverter<T>:CustomConverter<List<T>>
{
}
and
public class DictConverter<T,U>:CustomConverter<Dictionary<T,U>>
{
}
I used the same process to deal with them. But after I made a generic type CustomConverter<List<T>>, I found that ListConverter<T> does not derive from CustomConverter<List<T>> and CustomConverter<List<T>> is not assignable from
ListConverter<T>(which I checked with IsAssignableFrom() and IsSubclassOf()).
I guess the reason is that generic type stands for more than one type before the generic parameters are assigned.
This sounds weird but it is true. The compiler doesn't know that the T in CustomConverter<List<T>> and ListConverter<T> stand for the same TYPE
In fact, I can write it like CustomConverter<List<T>> and ListConverter<U>, and then you tell me the inheritance relationship between them.
And base type checking won't work here since ListConverter<T> and DictConverter<T,U> share the same root class. This means if I look for ListConverter<T>, I'll get DictConverter<T,U> too with the base class checking method(hierarchy loop checking). So I still have to make generic type, then check generic arguments and do type comparing.
The point is that I need to look for the specific class whose generic parameters are used as the generic arguments in its parent class's generic parameter. Sort of twisted but now it is clear.
Here is the final Convertion solution:
public static object ToObject(Type type, string value)
{
if (type == null)
throw new ArgumentNullException("type");
if (!typeof (IConvertible).IsAssignableFrom(type))
{
if (type.IsGenericType)
{
Type converterType = typeof (CustomConverter<>).MakeGenericType(type);
Type genericConverter =
typeof (ICustomConverter).Assembly.Types(Flags.Public)
.SingleOrDefault(
t =>
typeof (ICustomConverter).IsAssignableFrom(t) && t.IsGenericType &&
t.GetGenericArguments().Length == type.GetGenericArguments().Length && !t.IsAbstract &&
t.MakeGenericType(type.GetGenericArguments()).IsSubclassOf(converterType));
if (genericConverter != null)
{
Type customConverter = genericConverter.MakeGenericType(type.GetGenericArguments());
object instance = customConverter.CreateInstance();
if (instance is ICustomConverter)
return ((ICustomConverter) instance).CallConvert(value);
}
}
else
{
Type converterType = typeof (CustomConverter<>).MakeGenericType(type);
Type customConverter =
typeof (ICustomConverter).Assembly.Types(Flags.Public)
.SingleOrDefault(t => t.IsSubclassOf(converterType));
if (customConverter != null)
{
object instance = customConverter.CreateInstance();
if (instance is ICustomConverter)
return ((ICustomConverter) instance).CallConvert(value);
}
}
throw new ArgumentException("type is not IConvertible and no custom converters found", type.Name());
}
TypeConverter converter = TypeDescriptor.GetConverter(type);
return converter.ConvertFromString(value);
}
I also checked GetGenericArguments().Length in case List<T> messes with Dictionary<TKey,TValue>.
Note: some custom extension methods are used.
This question already has answers here:
Cast from Generics<T> to Specific SubClass
(9 answers)
Closed 7 years ago.
I have a simple interface and two classes implement it:
public interface IMovable { }
public class Human : IMovable { }
public class Animal : IMovable { }
The following generic 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 as keyword is used, all 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 as work but explicit cast doesn't?
Short answer is, because T doesn't have to be of the correct type. Compiler is really trying to help you here, because you are doing something which might easily fail in runtime.
E.g. consider what happens with:
var result = DoSomething<Human>("ANI");
Longer answer is, you shouldn't be casting at all. Casting indicates problems with your OOP design, and is especially wrong when using generics: you lose the whole point of generics, actually. Generics are supposed to allow you create a "template" which abstracts away the actual type, leaving you to worry about the algorithm itself instead of concrete types.
In this case, you probably don't need generics at all. Your method is basically a less safer way of doing this:
public static T DoSomething<T>() where T : new()
{
return new T();
}
or this:
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 may also add an intermediate cast, which tells the compiler you went an extra step to indicate that you really want to cast it this way: For example, using
(T)(object)new Human()
or
(T)(IMovable)new Human()
will both pass compilation, although the conversion from IMovable to T is no safer than the original code, and casting an object to T even unsafer. But this is not the solution to your underlying issue, which is design related.
With your code, it is perfectly possible to call DoSomething<Animal>, and then you have (Animal)new Human().
That is biologically correct, but your model does not allow it.
Do you really need generics here? Maybe you just want to return IMovable in this case.
Under the covers, the 'as' will do an 'is' check first before attempting the cast. So it will not attempt it if it can't cast it and will then return null.