I have a dictionary that I'm using to facilitate some internal routing based on api version numbers. Essentially what happens is that I look up and operation in the dictionary and attempt to call it's RUN method. But in order to do this, I need to be able to cast the object to it's interface. Here's what I mean, this is the dictionary:
public Dictionary<string, Type> Routing = new Dictionary<string, Type>();
public VersionRouter()
{
Routing.Add("1.0", typeof(OperationV1<RequestObjectV1, ResponseObjectV1>));
Routing.Add("2.0", typeof(OperationV1<RequestObjectV2, ResponseObjectV1>));
Routing.Add("3.0", typeof(OperationV1<RequestObjectV2, ResponseObjectV2>));
}
I can grab the correct type that I want to instantiate like so:
var myOperation = Routing["2.0"];
And then under normal circumstances, I'd just instantiate and cast it like this:
var myInstance = (MyInterface) Activator.CreateInstance(myOperation);
However, the interface is generic because it needs to know what the Request and Response types are:
var myInstance = (MyInterface<TRequest, TResponse>) Activator.CreateInstance(myOperation);
I don't know how to tell it what those request and response types are at this stage. I'm assuming it can be done with reflection. I've found that I can get those generic parameters out through something like myOperation.GetGenericArguments() but I'm not sure how to use that to my advantage at this stage. Does anyone know how to do this?
In order to expand on SLaks answer:
There is no logical way of dealing with your scenario. What you're trying to do is have a single piece of code work with different types at run time. This can only be done by building separate code branches (which can be done) or by falling back to dynamics/reflection. To clarify this:
class Apple { }
class Pear { }
void Handle(object what)
{
// either
if (what is Apple) {}
else if (what is Pear) {}
// or
dynamic x = what;
x.LetsHopeThisMethodExists();
// or
what.GetType().GetMethod('lorem').Invoke(what, null);
}
Now, we can stick with SLaks proposal of declaring a base type for both Apple
and Pear
, namely Fruit
. That way, Handle
can accept a Fruit
and perform logic on the common functionality available on both Apple
s and Pear
s.
That begs the question, how to do this with generics. Generics by default do not support variance, however in .NET 4.0, it's certainly possible. You can declare an interface (but only an interface) as covariant by applying the out
keyword on the type parameter. This allows you to do something like:
interface IFruit { }
interface IBasket<out TFruit> where TFruit : IFruit { }
class Apple : IFruit { }
class Pear : IFruit { }
class FruitBasket<TFruit> : IBasket<TFruit> where TFruit : IFruit { }
void Handle(IBasket<IFruit> what) { }
Handle(new FruitBasket<Apple>());
Handle(new FruitBasket<Pear>());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With