我有一个具有特定实现的通用接口,如下所示:
public class Animal { }
public class Horse : Animal { }
public class Dog : Animal { }
public interface Vet<in T> where T : Animal
{
void Heal(T animal);
}
public class HorseVet : Vet<Horse>
{
public void Heal(Horse animal)
{
Console.WriteLine("Healing a horse");
}
}
public class DogVet : Vet<Dog>
{
public void Heal(Dog animal)
{
Console.WriteLine("Healing a dog");
}
}
现在我希望能够在运行时给出 Animal
创建 Vet<T>
的相应具体实现的实例,如下所示:
StandardKernel kernel = new StandardKernel();
kernel.Bind<Vet<Horse>>().To<HorseVet>();
kernel.Bind<Vet<Dog>>().To<DogVet>();
var animals = new Animal[] { new Horse(), new Dog() };
foreach (Animal animal in animals)
{
// how do I get the right Vet<T> type here so I can call Heal(animal)?
}
我的问题是,如何实现上述目标以便检索正确的实现,或者我是否需要重构以不同的方式组织我的类?
我看过Ninject Factory Extension,但似乎也没有提供我正在寻找的东西 .
如果我没有使用IoC容器,我会做类似的事情:
public Vet<Animal> Create(Animal animal)
{
if (animal is Horse)
{
return new HorseVet();
}
else if ...
}
1 回答
但现在的问题是你想如何使用这种类型?你可能想做这样的事情:
但这不起作用,因为
Vet<Dog>
和Vet<Horse>
的实例无法转换为Vet<Animal>
,因为这需要Vet<T>
定义out
关键字,如Vet<out Animal>
. 但这当然行不通,因为Vet<T>
的输入参数类型为Animal
.因此,要解决此问题,您需要第二个非通用
Vet
接口,或者您需要使用反射或动态类型 . 使用非通用接口可能如下所示:然而问题是这会污染实现,因为它们突然需要实现第二种方法 .
另一种选择是使用动态类型或反射:
当然,缺点是您会失去编译时支持,但如果这两行代码是应用程序中唯一一个像这样调用兽医的行,我会说它很好 . 您可以轻松添加检查此代码的单元测试 .
请注意,
Vet<in T>
上的in
关键字可能没用,除非您在Dog
和GoldenRetriever
上都有兽医实施,并且希望能够将GoldenRetriever
应用于Vet<Dog>
.