.NET泛型:如何在运行时解析类型T?

YMC*_*YMC 7 .net c# generics c#-4.0

让我在下面的例子中解释一下我正在解决的问题:

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 !");
    }
}
Run Code Online (Sandbox Code Playgroud)

所以现在我想通过所有动物并运行这样的适当处理程序:

  var ah = new AnimalHandler();
  var animals = new List<Animal> { new Cat(), new Dog() };
  animals.ForEach(a => ah.Handle(a));
Run Code Online (Sandbox Code Playgroud)

但是这个代码不起作用(无法解析方法Hanler <> ...)只是因为.NET编译器需要在编译之前知道这里使用了哪种类型,那么这个问题的最佳解决方案是什么?换句话说,我需要让.NET编译器在运行时为类型T的每个实例采用类型为T的适当处理程序.我不想使用多个if语句检查实例类型.

更新:很抱歉错过了它,这对我来说似乎很明显,但现在我明白它并不那么明显:AnimalHandler类包含的逻辑不应该是域对象Cat和Dog的一部分.将它们视为纯粹的纯域对象,我不希望它们知道任何类型的处理程序

Dan*_*iel 8

您可以使用C#4 dynamic将重载解析步骤从编译时移动到运行时:

var ah = new AnimalHandler();
var animals = new List<Animal> { new Cat(), new Dog() };
animals.ForEach(a => ah.Handle((dynamic)a));
Run Code Online (Sandbox Code Playgroud)


Sha*_*mer 5

对我来说,听起来你可以从这种模式中受益(使用StructureMap实现).从原始语句开始,"我需要让.NET编译器在运行时为T类型的每个实例采用类型为T的适当处理程序"它可能看起来像这样:

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
    }
}    
Run Code Online (Sandbox Code Playgroud)

然后,您可以根据链接的文章配置StructureMap,并使用以下命令获取相应的处理程序:

var dogHandler = _container.GetInstance<IHandler<Dog>>(); // instance of DogHandler
var catHandler = _container.GetInstance<IHandler<Cat>>(); // instance of CatHandler
Run Code Online (Sandbox Code Playgroud)

更新:要在循环中解决这些问题,您可以执行以下操作:

foreach (var animal in animals)
{
    var concreteHandlerType = typeof(IHandler<>).MakeGenericType(animal.GetType());
    var handler = _container.GetInstance(concreteHandlerType);
    handler.Handle(animal);
}
Run Code Online (Sandbox Code Playgroud)

我在一个相当大的系统中使用这个模式来实现相同的目标(纯域对象,逻辑处理程序不应该在那些域对象内,简化维护).它适用于您希望为每个对象都有一个单独的处理程序类的系统.