I’ve got an instance of class B, which is a specialisation of an abstract class A<TInput, TOutput>. There are several variants of class B, as I’ve implemented it with a variety of input and outputs.
TInput and TOutput are constrained to specific input and output classes, let’s call them I and O.
I am instantiating B by using Activator.CreateInstance, but since it returns an object, I need to to cast it to A<I, O>. I expect this to work as I and O are base classes (in this case B<SpecialisationOfI, SpecalisationOfO>).
This is where it fails as this cast is apparently invalid.
Pseudo code:
abstract class I { }
abstract class O { }
abstract class A<TInput, TOutput>
where TInput : I
where TOutput : O
{
abstract TOutput Foo(TInput bar);
}
class Input : I { }
class Output : O { }
class B : A<Input, Output> { }
A<I, O> instance = (A<I, O>)Activator.CreateInstance(typeOfB); // <-- fail
instance.Foo(input);
Is it possible to make this work? Thank you!
edit Based on the answer that I was given, I’ve solved this by restructuring the code significantly based on the covariance: I moved Foo from A to an interface:
interface IA<TResult> {
TResult Foo(object input);
}
class A<TInput, TOutput> : IA<TOutput>
where TInput : I
where TOutput : O {
public TOutput Foo(object input) {
if (!(input is TInput)) {
throw new ArgumentException("input");
}
return FooImpl(input as TInput);
}
protected abstract TOutput FooImpl(TInput input);
}
var instance = (IA<Output>) Activator.CreateInstance(type);
instance.Foo(input);
Thank you for sharing your insight with me!
This has nothing to do with how you’re creating the instance – it’s a problem with generic variance. What you’re essentially trying to do is similar to this:
And the reason it’s not valid is that the next line of code might (in general) be:
If that’s trying to add to a list which is really of type
List<string>, that’s bad news.Now if you change from an abstract class to an interface, and if you’re using C# 4, you can use generic covariance and generic contravariance:
That’s still not going to work for your code though, as you’re trying to use both input and output covariantly. Your
Bclass will have a method like this:… in other words, it needs input of type
Input. But if you’ve got anA<I, O>that should be able to work for any implementation ofI: