4

我有一个Company包含不同列表的类IFactory<IPart>;例如一个EngineFactory.

public class Company
{
    private Dictionary<Type, IFactory<IPart>> _factories;

    public Company()
    {
        _factories = new Dictionary<Type, IFactory<IPart>>();
        _factories[typeof (Engine)] = new EngineFactory();
    }

    public void SendOrderIntakeToFactory(IPart part)
    {
    }
}

EngineFactory看起来像这样:

public class EngineFactory : IFactory<Engine> 
{
    public void Produce(Engine part)
    {
    }
}

IFactory界面:

public interface IFactory<T> where T : IPart
{
    void Produce(T part);
}

这将导致编译器错误:

无法将类型“EngineFactory”隐式转换为“IFactory”。存在显式转换(您是否缺少演员表?)

在这条线上:_factories[typeof (Engine)] = new EngineFactory();

好的,这对我来说很有意义,如果不指定方差,这将永远不会起作用。所以我尝试将out关键字添加到泛型类型T,但这将迫使我删除Tas 方法参数(因为它不允许<out T>用作输入参数):

public interface IFactory<out T> where T : IPart
{
    void Produce(IPart part);
}

这显然打破了我的通用设计。我能够Wheel在我的EngineFactory.

我理解挑战在于这两个要求:

  • 将工厂存储为IFactory<IPart>
  • void Produce(T part);在工厂中需要一个通用的实现。

有没有办法做到这一点?

4

3 回答 3

2

如果泛型类型参数仅用作方法的返回类型,则可以将其标记为协变。更改Produce方法以返回部分,一切都会起作用

public interface IFactory<out T> where T : IPart
{
    T Produce();
}

如果将协变类型参数用作方法参数,则不能使用它。

顺便说一句,这是一个非常奇怪的工厂,它接受对象而不是创建它们。


更新您可以将运行时类型定义与动态一起使用:

public class Company
{
    private Dictionary<Type, dynamic> _factories;

    public Company()
    {
        _factories = new Dictionary<Type, dynamic>();
        _factories[typeof(Engine)] = new EngineFactory();
    }

    public void SendOrderIntakeToFactory(IPart part)
    {
        _factories[part.GetType()].Produce((dynamic)part);
    }
}

你什么时候打电话

company.SendOrderIntakeToFactory(new Engine());

然后EngineFactory将被选中,并Produce使用运行时类型的参数调用它的方法Engine

于 2013-03-17T10:18:47.003 回答
2

我想你可以稍微放松一下字典。考虑以下“工厂容器”:

public class Factories
{
    private Dictionary<Type, object> _factories;

    public Factories()
    {
        _factories = new Dictionary<Type, object>();
        _factories[typeof (Engine)] = new EngineFactory();
    }

    public IFactory<TPart> GetFactory<TPart>() where TPart:IPart
    {
        //TODO: add check whether typeof(TPart) exist in the dictionary
        return (IFactory<TPart>)_factories[typeof(TPart)];
    }
}

此实现将允许您执行以下操作:

var factories = new Factories();
var engineFactory = factories.GetFactory<Engine>();
var engine = new Engine();
engineFactory.Produce(engine);
于 2013-03-17T10:46:37.267 回答
0

你特别想做的(混合协方差和逆变)是一个兔子洞。唯一的解决方案是不要像这样混合方差;当您觉得需要混合方差时,请转到运行时类型检查。

[更新] 这将解决两个问题(强类型和灵活的位置)

interface IPart{}
class Engine : IPart{} 

interface IMachine
{
    void Produce(IPart part);
    Type Type { get; }
}

interface IGenericMachine<in TPart> : IMachine
{
    void Produce(TPart with);
}

class EngineMachine : IGenericMachine<Engine>
{
    public void Produce(Engine with)
    {
    }

    public void Produce(IPart part)
    {
        if (part.GetType() != typeof(Engine))
            throw new ArgumentException("part must be an Engine");
    }

    public Type Type { get { return typeof (Engine); } }
}

internal class MachineLocator
{
    public Dictionary<Type, IMachine> Machines;

    public IGenericMachine<TPart> GetMachine<TPart>()
    {
        return Machines
            .Select(x => x.Value)
            .OfType<IGenericMachine<TPart>>()
            .Single();
    }

    public IMachine GetMachine(Type type)
    {
        return Machines
            .Where(x => x.Value.Type == type)
            .Select(x=>x.Value)
            .Single();
    }
}

class Program
{
    static public void Main()
    {
        var locator = new MachineLocator();

        locator.Machines.Add(typeof(EngineMachine), new EngineMachine());

        var machineKnown = locator.GetMachine<Engine>();
        var machineUnknown = locator.GetMachine(typeof(Engine));

        machineUnknown.Produce(new Engine());
    }
}

当一切已经说过并且做完了; 看一下控制反转作为一般程序的更好设计模式。基本上类不寻找东西,他们得到它。

于 2013-03-17T11:22:55.790 回答