c# - 通用工厂问题、运行时转换和协变/逆变问题

标签 c# .net generics factory

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

我准备了一些 self 解释的代码:

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/contravariant 所以定义接近:(source)

Covariance

Enables you to use a more derived type than originally specified.

You can assign an instance of IEnumerable< Derived> to a variable of type IEnumerable< Base>.

Contravariance

Enables you to use a more generic (less derived) type than originally specified.

You can assign an instance of Action< Base> to a variable of type Action< Derived>.

您的动物管理员定义为 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> 类型的不太通用(或更具体)的变量.

关于c# - 通用工厂问题、运行时转换和协变/逆变问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58415949/

相关文章:

c# - 在 C# WinForms 中引发自定义事件

.net - 像 Reflective 这样的 .NET 反汇编程序可以访问原始源代码中的注释吗?

swift - 存储通用类型的项目

c# - C# 中长值的枚举

c# - SQL Server 集成测试验证使用 AutoFixture 创建的日期时间

C# Math.Sqrt() 不工作

c# - 具有统一 BorderThickness 的边框无法绑定(bind) BorderBrush 颜色

c# - 从专有名称中提取通用名称

c# - 抽象类的嵌套列表<>属性

java - 不同对象的通用 Activity