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が、 as メソッド パラメーターを削除する必要があります (入力パラメーターとしてTの使用が許可されていないため)。<out T>

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

これは明らかに私の一般的な設計を破っています。で を生産できWheelますEngineFactory

この課題は、次の 2 つの要件にあることを理解しています。

  • ファクトリを次のように保存しますIFactory<IPart>
  • void Produce(T part);工場での一般的な実装の必要性。

これを達成する方法はありますか?

4

3 に答える 3

2

メソッドの戻り値の型としてのみ使用される場合は、ジェネリック型パラメーターを共変としてマークできます。メソッドを変更Produceして一部を返却すると、すべてが機能します

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

メソッド パラメーターとして使用する場合、共変型パラメーターを使用することはできません。

ところで、オブジェクトを作成する代わりに受け入れるのは、本当に奇妙なファクトリです。


UPDATE動的でランタイム型定義を使用できます:

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 に答える