2017-03-19 1 views
0

を使用して一般名を持つ具体的なオブジェクトを動的に選択します。exampleは、簡単なオブジェクト階層の登録と解決をSimpleInjectorで示しています。階層内にジェネリックタイプ(Shippercontract)を追加すると、これはどのように解決できますか?シンプルインジェクタ

考慮事項:

  1. contractcsvファイルとして解析され、彼らは、UPSやフェデックスのための全く異なる場合があります。 UPSとFedExのクラスだけが出荷前に契約書で何を探すべきかを知っています。ビジネスは契約をいつでも更新してフォルダにドロップできるため、契約はCSVから読み込まれます。アプリが契約の変更の結果として開始されるべきではありません。

  2. UPSやFedExを通知などの依存関係でテストしたい(コード内ではない)。

  3. この例で使用しているregisterresolveは間違っていると考えてください。クラス階層のみを考慮する必要があります。

次の部分のコードです:

public Setup() 
{ 
    var container = new SimpleInjector.Container(); 
    // TODO: Registration required for two different shippers 
    container.Register<UPS, IShipper>(); 
} 

public interface IShipper<T> 
{ 
    T contact; 
    void Ship(Product product); 
    T ParseContract(string fileName); 
    void SetContract(T); 
} 

public class FiveYearContract 
{ 
    public string IsSigned { get; set; } 
} 

public class TenYearContract 
{ 
    public string IsPrepaid { get; set; } 
} 

public interface IUPS<T> : IShipper<T> { } 
public interface IFedEx<T> : IShipper<T> { } 

public class UPS : IUPS<FiveYearContract> { ... } 
public class FedEx : IFedEx<TenYearContract> { ... } 

使用法:

public void Ship(String shipper, Product product) 
{ 
    // TODO: Retrieve the shipper by name 
    var shipper = container.GetInstance<IShipper>(); 
    shipper.SetContract(shipper.ParseContract("contract.csv"); 
    // Contract will be checked before sending 
    shipper.Ship(product); 
} 

Ship("FedEx", new Product()); 
+1

質問がありません。一般的な 'IShipper 'を定義しますが、この例では非汎用的な 'IShipper'インタフェースを解決します。 'IShipper 'は 'IShipper'から継承していますか? – Steven

+1

2番目の質問:各呼び出しで変更される可能性のある実行時データ、またはアプリケーションが再起動されるまで変更される予定のアプリケーション構成の一部です。 – Steven

+0

@スティーブンポイント3と1を参照してください。 –

答えて

1

コンパイル時にTが不明であるIShipper<T>を解決することができるようにするには、次の手順を実行する必要があります反射を使用します。例えば:

public Setup() 
{ 
    container.Register(typeof(IShipper<>), new[] { typeof(FedEx).Assembly }); 
} 

public void Ship(String shipper, Product product) 
{ 
    var contract = shipper.ParseContract("contract.csv"); 

    dynamic shipper = container.GetInstance(
     typeof(IShipper<>).MakeGenericType(contract.GetType())); 

    shipper.SetContract((dynamic)contract); 

    shipper.Ship(product); 
} 

SetContract方法しかしながら、荷主実装は可変なることを引き起こし、それがTemporal Couplingを引き起こします。優れたデザインは、一般的に次のように、Ship方法にcontractランタイム値を渡すために、次のようになります。

public void Ship(String shipper, Product product) 
{ 
    var contract = shipper.ParseContract("contract.csv"); 

    dynamic shipper = container.GetInstance(
     typeof(IShipper<>).MakeGenericType(contract.GetType())); 

    shipper.Ship((dynamic)contract, product); 
} 

これはIShipper<T>実装は不変滞在することができます(かなりあなたのアプリケーションを簡素化することができます)との間の暗黙的な関係を削除しますSetContractおよびShipの方法。これらの実装をテストするのが容易になる可能性が最も高いです。

関連する問題