typeof(T)
is correct here.
I tested your case, and typeof(T)
always returns the "true" class, not just the type requirement.
public class BaseClass { }
public class DerivedClass: BaseClass { }
public class GenericClass<T> where T : BaseClass
{
public string TypeOf = typeof(T).ToString();
}
public class GenericSuperClass<T> where T : BaseClass
{
public GenericClass<T> Sub = new GenericClass<T>();
}
static void Main(string[] args)
{
Console.WriteLine("1 - " + (new GenericClass<BaseClass>()).TypeOf);
Console.WriteLine("2 - " + (new GenericClass<DerivedClass>()).TypeOf);
Console.WriteLine("3 - " + (new GenericSuperClass<BaseClass>()).Sub.TypeOf);
Console.WriteLine("4 - " + (new GenericSuperClass<DerivedClass>()).Sub.TypeOf);
Console.ReadLine();
}
The output:
1 - BaseClass
2 - DerivedClass
3 - BaseClass
4 - DerivedClass
Note that I've simplified the classnames from the values that are actually returned (e.g Sandbox.TestConsole.Program+DerivedClass
).
This directly contradicts your claim that you only ever get the base type (AggregateRoot
, in your case).
Reflection is an exception to this.
I can think of one exception to this: when your type is only defined at runtime (e.g. generated from a type name (String
)).
However, as this StackOverflow answer explains, generics are intended to provide compile time type safety.
It's not impossible to use reflection to instantiate a generic class at runtime. But when you do so, you are inherently preventing the validity of information (e.g. type names) that are decided at compile-time.
MSDN's page on typeof implicitly states that the return value of typeof
is the compile-time type.
Combining these two facts, this means that when you use reflection (i.e. deciding the type at runtime), you cannot rely on typeof
(as this returns the compile time type).
The linked MSDN page also mentions how to find the runtime type:
To obtain the run-time type of an expression, you can use the .NET Framework method GetType, as in the following example:
int i = 0;
System.Type type = i.GetType();
However, do note that the GetType()
method is only available on an instantiated object, not on a generic type parameter. Generic type parameters are not really types, they are much closer to "type placeholders".
You will need either pass the type as a parameter, or an instantiated object (of the appropriate type).
Conclusion:
If you are using types that are known at compile time, then you can simply use typeof(T)
, as my example has shown.
If you are deciding the type on runtime using reflection, then you cannot rely on the information provided by typeof(T)
, and will therefore be required to supply the type. Either you supply it as a Type
parameter, or you supply it via an instantiated object, whose runtime type can accurately be tested using the GetType()
method.
However, if you are already deciding the type on runtime, then you are better off passing the type itself as a parameter. If you're using reflection here, that means that you must at some point have known which type you wanted to use. Therefore, simply pass that known type as a parameter, which you can then use for your subsequent business logic.
I cannot think of a single scenario in which you aren't either (a) using a type that is known at compile time, nor (b) aware (at runtime) of the type you've decided to use.