简体   繁体   English

如何指向基础类<T>在通用工厂

[英]How to point to underlying class of <T> in generic factory

Got some vegetables going on:吃了些蔬菜:

public interface IVegetable
{

}

public class Potato : IVegetable
{

}

public class Onion : IVegetable
{

}

We'd focus on the onion and process it: I have single generic interface for a generic vegetable processor and one onion-specific:我们将专注于洋葱并对其进行处理:我有一个通用蔬菜处理器的通用接口和一个特定于洋葱的接口:

public interface IVegetableProcessor<T> where T : IVegetable
{
    string GetColor(T vegetable);
}

public interface IOnionProcessor : IVegetableProcessor<Onion>
{
    void MakeCry(Onion onion);
}

public class OnionProcessor : IOnionProcessor
{
    public string GetColor(Onion onion)
    {
        return "Purple";
    }

    public void MakeCry(Onion onion)
    {
        Console.WriteLine($"{onion} made you cry!");
    }
}

As well as a generic factory:以及通用工厂:

interface IVegetableProcessorFactory
{
    IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}

internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
    public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
    {
        object processor = vegetable switch
        {
            Onion => new OnionProcessor(),
            _ => throw new NotImplementedException($"Other vegetables not here yet")
        };

        return (IVegetableProcessor<T>)processor; //this will fail later
    }
}

And finally this does not work:最后这不起作用:

static void Main(string[] args)
{
    var onion = new Onion() as IVegetable;
    var factory = new VegetableProcessorFactory();

    var processor = factory.GetVegetableProcessor(onion);

    Console.WriteLine(processor.GetColor(onion));
    Console.ReadLine();
}

The error is:错误是:

System.InvalidCastException: 'Unable to cast object of type 'OnionProcessor' to type 'IVegetableProcessor`1[Vegetables.Program+IVegetable]'.'

How to make it understand the underlying class of IVegetable and cast the processor to it's corresponding type?如何让它理解 IVegetable 的底层类并将处理器转换为它的相应类型?

Your input is already contravariant, but by casting your Onion instance to IVegetable , it is no longer able to be cast back to IVetetableProcessor<T> in your factory, because at that point you need IVetetableProcessor<Onion> , but what you have is a IVegetableProcessor<IVegetable> , and your interface is not covariant.您的输入已经是逆变的,但是通过将您的 Onion 实例转换为IVegetable ,它不再能够在您的工厂中被转换回IVetetableProcessor<T> ,因为此时您需要IVetetableProcessor<Onion> ,但是您拥有的是IVegetableProcessor<IVegetable> ,并且您的界面不是协变的。

By simply removing your initial cast of new Onion to IVegetable , your code works as is:通过简单地将new Onion的初始转换删除到IVegetable ,您的代码将按原样工作:

static void Main(string[] args)
{
    var onion = new Onion();
    var factory = new VegetableProcessorFactory();

    var processor = factory.GetVegetableProcessor(onion);

    Console.WriteLine(processor.GetColor(onion));
    Console.ReadLine();
}

public interface IVegetable { }
public class Potato : IVegetable { }
public class Onion : IVegetable { }

public interface IVegetableProcessor<T> where T : IVegetable
{
    string GetColor(T vegetable);
}

public interface IOnionProcessor : IVegetableProcessor<Onion>
{
    void MakeCry();
}

public class OnionProcessor : IOnionProcessor
{
    public string GetColor(Onion vegetable)
    {
        return "Purple";
    }

    public void MakeCry()
    {
        Console.WriteLine("You cry now!");
    }
}

interface IVegetableProcessorFactory
{
    IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}

internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
    public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
    {
        var processor = vegetable switch
        {
            Onion => new OnionProcessor(),
            _ => throw new NotImplementedException($"Other vegetables not here yet")
        };

        return (IVegetableProcessor<T>)processor;
    }
}

The fact that you have to cast in the first place is your hint that something is broken in your composition.你必须首先投射的事实是你暗示你的作品中有什么东西被破坏了。 As Selvin mentioned in the comments, implementing IVegetableProcessor<Onion> is NOT the same thing as implementing IVegetableProcessor<IVegetable> .正如 Selvin 在评论中提到的,实现IVegetableProcessor<Onion>与实现IVegetableProcessor<IVegetable>

Your processor interfaces should implement IVegetableProcessor<IVegetable> and take IVegetable instances, allowing contravariance for the input parameters:您的处理器接口应该实现IVegetableProcessor<IVegetable>并采用 IVegetable 实例,允许输入参数的逆变:

public interface IVegetableProcessor<T> where T : IVegetable
{
    string GetColor(T vegetable);
}

public interface IOnionProcessor : IVegetableProcessor<IVegetable>
{
    void MakeCry();
}

public class OnionProcessor : IOnionProcessor
{
    public string GetColor(IVegetable vegetable)
    {
        return "Purple";
    }

    public void MakeCry()
    {
        Console.WriteLine("You cry now!");
    }
}

interface IVegetableProcessorFactory
{
    IVegetableProcessor<IVegetable> GetVegetableProcessor(IVegetable vegetable);
}

internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
    public IVegetableProcessor<IVegetable> GetVegetableProcessor(IVegetable vegetable)
    {
        var processor = vegetable switch
        {
            Onion => new OnionProcessor(),
            _ => throw new NotImplementedException($"Other vegetables not here yet")
        };

        return processor;
    }
}

This correctly outputs "Purple" when run via:通过以下方式运行时,这会正确输出“Purple”:

static void Main(string[] args)
{
    var onion = new Onion();
    var factory = new VegetableProcessorFactory();

    var processor = factory.GetVegetableProcessor(onion);

    Console.WriteLine(processor.GetColor(onion));
    Console.ReadLine();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM