泛型工厂问题、运行时转换和协变/逆变问题



我做了几年的开发人员,但似乎我仍然不了解一些关于泛型的高级知识。

我准备了一些不言自明的代码:

public enum AnimalType { Cat, Dog}
public interface IAnimal { }
public class Dog : IAnimal { }
public class Cat : IAnimal { }
public interface IAnimalHandler<in TAnimal> where TAnimal : IAnimal { void Handle(TAnimal animal); }
public class CatHandler : IAnimalHandler<Cat>
{
public void Handle(Cat animal) { }
}
public class DogHandler : IAnimalHandler<Dog>
{
public void Handle(Dog animal) { }
}
public class AnimalFactory
{
public IAnimal GetAnimal(AnimalType type) { return type == AnimalType.Cat ? (IAnimal) new Cat() : (IAnimal)new Dog();}
}
public class AnimalHandlerFactory
{
public IAnimalHandler<TAnimal> GetAnimalHandler<TAnimal>(TAnimal animal) where TAnimal : IAnimal
{
switch (animal)
{
case Cat cat:
return new CatHandler() as IAnimalHandler<TAnimal>;
case Dog dog:
return new CatHandler() as IAnimalHandler<TAnimal>;
default:
throw new Exception();
}
}
}
public class FactoryTests
{
[Fact]
public async Task factory_returns_concrete()
{
var myAnimal = new AnimalFactory().GetAnimal(AnimalType.Dog);
var handlerForMyAnimal = new AnimalHandlerFactory().GetAnimalHandler(myAnimal);
Assert.NotNull(handlerForMyAnimal);
}
}

现在,请你回答我的疑问吗?

1( 为什么我必须在GetAnimalHandler((方法中执行转换?

2(测试失败,因为AnimalFactory返回一个抽象对象(声明(,并且此类型用作GetAnimalHandler((方法的泛型类型,因此显然转换返回的null。问题是如何解决这个问题?我错过了一些模式吗?

您是正确的,您缺少有关co/contravariary的某些内容,因此在附近具有定义:(来源(

协方差

使您能够使用比最初指定的派生类型更多的类型。

您可以将 IEnumerable的实例分配给 IEnumerable类型的变量。

逆变

使您能够使用比原始类型更通用(派生较少(的类型 指定。

您可以将 Action

的实例分配给类型为 Action的变量。

你用in定义了你的动物处理员,这使得它与变相矛盾。所以根据你的定义,这是合法的

IAnimalHandler<PersianCat> handler = new CatHandler();

鉴于

public class PersianCat : Cat { }

如果你仔细想想,如果你是一个猫处理员,而不是你可以处理波斯猫,这是有道理的。你处理的是什么样的猫,你可以处理它们,这对你来说没有区别。

您试图强迫的情况是不合法的:

IAnimalHandler<IAnimal> handler = new CatHandler();

使用我的波斯猫(和专门的处理者(,它看起来像这样:

IAnimalHandler<Cat> handler = new PersianCatHandler();

所以我们有专门的训导员,只能处理波斯猫,所以我们不能给他一只随机的猫,他不知道该怎么处理它。

因此,在法律案例中,more generic类型的逆变定义位于赋值的右侧,CatHandler(或IAnimalHandler<Cat>(,并分配给类型IAnimalHandler<PersianCat>的不太通用(或更具体(的变量。

最新更新