我做了几年的开发人员,但似乎我仍然不了解一些关于泛型的高级知识。
我准备了一些不言自明的代码:
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>
的不太通用(或更具体(的变量。