Let me explain you in the following example what problem I'm solving:
class Animal {}
class Cat: Animal {}
class Dog : Animal { }
interface IAnimalHandler<in T> where T: Animal
{
void Handle(T animal);
}
class AnimalHandler :
IAnimalHandler<Cat>,
IAnimalHandler<Dog>
{
public void Handle(Cat animal)
{
Console.Write("it's a cat !");
}
public void Handle(Dog animal)
{
Console.Write("it's a dog !");
}
}
So now I want go through all animals and run appropriate handler like this:
var ah = new AnimalHandler();
var animals = new List<Animal> { new Cat(), new Dog() };
animals.ForEach(a => ah.Handle(a));
However this code would not work (Can not resolve method Hanler<>...) just because .NET compiler needs to know before compilation which type is used here, so what might be the best solution for this issue? In other words, I need to ask .NET compiler to take appropriate handler of type T for every instance of type T in run-time.
I do not want to use multiple if
statements checking instance type.
UPDATE: Sorry for missing it, it seemed obvious to me, but now I understand it's not so obvious: AnimalHandler class contains logic not supposed to be part of domain objects Cat and Dog. Think about them as pure plain domain objects, I do not want them to know about any sort of handlers
You can get the Type that represents T , and use the IsInterface property: Type type = typeof(T); if (type. IsInterface) { ... } If you want to know which interface is passed, just use == to compare the Type objects, e.g.
However, according to this answer, in C#, the generic type is resolved at compile time.
Due to type erasure, there are no generics at runtime. It is all compile-time type checking.
T is called type parameter, which can be used as a type of fields, properties, method parameters, return types, and delegates in the DataStore class. For example, Data is generic property because we have used a type parameter T as its type instead of the specific data type. Note.
You can use C# 4 dynamic
to move the overload resolution step from compile-time to runtime:
var ah = new AnimalHandler();
var animals = new List<Animal> { new Cat(), new Dog() };
animals.ForEach(a => ah.Handle((dynamic)a));
To me it sounds like you could benefit from this pattern (implemented using StructureMap). Going from your original statement, "I need to ask .NET compiler to take appropriate handler of type T for every instance of type T in run-time" it might look something like this:
class Dog : Animal { }
class Cat : Animal { }
interface IHandler<T>
{
void Handle(T eval);
}
class DogHandler : IHandler<Dog>
{
public void Handle(Dog eval)
{
// do whatever
}
}
class CatHandler : IHandler<Cat>
{
public void Handle(Cat eval)
{
// do whatever
}
}
You could then configure StructureMap as per the linked article, and get the appropriate handler using:
var dogHandler = _container.GetInstance<IHandler<Dog>>(); // instance of DogHandler
var catHandler = _container.GetInstance<IHandler<Cat>>(); // instance of CatHandler
UPDATE: To resolve these in a loop you could do something like this:
foreach (var animal in animals)
{
var concreteHandlerType = typeof(IHandler<>).MakeGenericType(animal.GetType());
var handler = _container.GetInstance(concreteHandlerType);
handler.Handle(animal);
}
I use this pattern in a fairly large system to accomplish the same goals (pure domain objects, handlers for logic that should not be inside those domain objects, simplified maintenance). It works well in a system where you want to have a separate handler class for each object.
Exactly your code, but using reflection:
var ah = new AnimalHandler();
var animals = new List<Animal> { new Cat(), new Dog() };
animals.ForEach(a => {
var method = ah.GetType().GetMethod("Handle", new Type[] {a.GetType()});
method.Invoke(ah,new object[] { a });
});
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