Reputation: 11155
When I use reflection in this case, the created type can be many generic types.
BaseStepHandler<BaseStepDataModel> activator = (BaseStepHandler<BaseStepDataModel>)Activator.CreateInstance(....);
The created instance can be all childs of BaseStepDataModel.
BaseStepHandler<OneDataModel>
OR
BaseStepHandler<TwoDataModel>
OneDataModel and TwoDataModel are extending BaseStepDataModel.
this is the exception that I get:
Unable to cast object of type '....GlobalOnBoardingStepOneHandler' to type '....BaseStepHandler`1[....BaseStepDataModel]'.
this is the declaration if GlobalOnBoardingStepOneHandler.
public class GlobalOnBoardingStepOneHandler : BaseStepHandler<GlobalOnBoardingStepOneDataModel>{}
Upvotes: 3
Views: 4328
Reputation: 64923
Problem here is you're expecting contravariance covariance for concrete type generic parameters.
Basically, you won't never achieve your goal using a concrete type, but there's a workaround for this.
You can design a marker interface like this:
public interface IBaseStepHandler<out T> // "out" marks T as covariant
where T : BaseDataModel // Do you have a model base type? ;)
{
// Declare members here
}
Where I say "declare members here", just declare such members which are part of your concrete base class (I'm talking about "BaseStepHandler").
After that, implement this interface in your base class BaseStepHandler.
Now, you can do what you want:
IBaseStepHandler<BaseDataModel> some = new WhateverBaseStepHandlerClass();
// This is possible because T generic parameter is covariant and it can be casted to `BaseDataModel`, or if you don't provide a `T` generic parameter constraint, you could cast it to `IBaseStepHandler<object>` too!
In order to learn more about covariance, follow this link: http://msdn.microsoft.com/en-us/library/ee207183.aspx
Upvotes: 5
Reputation: 51329
You are getting the exception because GlobalOnBoardingStepOneHandler
inherits from BaseStepHandler<GlobalOnBoardingStepOneDataModel>
, not BaseStepHandler<BaseStepDataModel>
. This is probably the most common mistake with .NET generics. Generics are not covariant for type parameters.
See:
C#: cast to generic interface with base type
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
etc...
The issue is that you assume that because GlobalOnBoardingStepOneDataModel
inherits from BaseStepDataModel
, that GlobalOnBoardingStepOneHandler
inherits from BaseStepHandler<BaseStepDataModel>
. That simply isn't the case, and so you can't cast from one to the other.
As an example, consider the following:
var myListOfStrings = new List<String>();
// By your logic, this should compile (it doesn't):
var myListOfObjects = ((List<Object>)myListOfStrings);
// But if it did, this would be possible:
myListOfObjects.Add(1); // Holy cow, I just added an integer to a list of strings! What is the world coming to?
Now, this is very confusing for recovering Java programmers because this is possible in Java. In Java, you have type erasure, so that at runtime a List<String>
is actually just a List<Object>
, and so you can cast it to anything you like, and put anything you want into it. Because the CLR uses reified generics, not type erasure, a List<String>
is actually a separate and distinct type from a List<Object>
or a List<Integer>
Upvotes: 4