C# 一般工厂问题、运行时强制转换和co/逆变问题

C# 一般工厂问题、运行时强制转换和co/逆变问题,c#,.net,generics,factory,C#,.net,Generics,Factory,我作为一名开发人员工作了几年,但似乎我仍然不了解有关泛型的一些高级内容 我准备了一些不言自明的代码: public enum AnimalType { Cat, Dog} public interface IAnimal { } public class Dog : IAnimal { } public class Cat : IAnimal { } public interface IAnimalHandler<in TAnimal> where TAnimal : IAnima

我作为一名开发人员工作了几年,但似乎我仍然不了解有关泛型的一些高级内容

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

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);
    }
}
public enum AnimalType{Cat,Dog}
公共接口IAnimal{}
公家犬:IAnimal{}
公共类Cat:IAnimal{}
公共接口IAnimalHandler,其中TAnimal:IAnimal{void Handle(TAnimal animal);}
公共类CatHandler:IAnimalHandler
{
公共空柄(猫科动物){}
}
公共类DogHandler:IAnimalHandler
{
公共空柄(狗类动物){}
}
公营畜牧业
{
public IAnimal GetAnimal(AnimalType){return type==AnimalType.Cat?(IAnimal)new Cat():(IAnimal)new Dog();}
}
公营动物手工厂
{
公共IAnimalHandler GetAnimalHandler(TAnimal动物),其中TAnimal:IAnimal
{
开关(动物)
{
案例类别:
将新的CatHandler()作为IAnimalHandler返回;
个案狗只:
将新的CatHandler()作为IAnimalHandler返回;
违约:
抛出新异常();
}
}
}
公共类工厂测试
{
[事实]
公共异步任务工厂\u返回\u具体()
{
var myAnimal=newanimalfactory().GetAnimal(AnimalType.Dog);
var handlerForMyAnimal=新的AnimalHandlerFactory().GetAnimalHandler(myAnimal);
Assert.NotNull(handlerForMyAnimal);
}
}
现在,你能回答我的疑问吗

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


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

你是正确的,你遗漏了一些关于co/逆变的内容,因此在以下位置有了定义:()

协方差

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

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

对冲

使您能够使用比最初更通用(派生更少)的类型 指定的

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

您在中用
定义了您的动物处理程序,这使其具有反变性。根据你的定义,这是合法的

IAnimalHandler<PersianCat> handler = new CatHandler();
如果你想一想,如果你是一个驯养猫的人,你就可以驯养波斯猫。不管你在对付什么样的猫,你都能对付它们

您试图强制执行的案件不合法:

IAnimalHandler<IAnimal> handler = new CatHandler();
IAnimalHandler handler=new CatHandler();
使用我的波斯猫(和专用的处理程序),它看起来是这样的:

IAnimalHandler<Cat> handler = new PersianCatHandler();
IAnimalHandler handler=new PersianCatHandler();
所以,我们有专门的处理程序,只能处理波斯猫,所以我们不能给他只是一个随机的猫,他不知道该怎么办

因此,在法律案例和上文的逆变定义中,
更通用的
类型位于赋值的右侧,
CatHandler
(或
IAnimalHandler
),它被赋值给
IAnimalHandler
类型的非通用(或更具体)变量

IAnimalHandler<Cat> handler = new PersianCatHandler();