2016-03-29 9 views
3

私はC#でUnityを使用しています。私はIConnectionStringLoaderと呼ばれるインターフェースを持っていて、2つの派生インターフェースを持っています。ユニティ登録が互いにオーバーライドします

​​

1つだけの実装を持っている:私の登録は、このようになります

public class ConnectionStringLoader : IDbConnectionStringLoader, IMetaDataConnectionStringLoader 
{ 
    private readonly string _connectionStringName; 

    public ConnectionStringLoader(string connectionStringName) 
    { 
     _connectionStringName = connectionStringName; 
    } 

    public string Get() 
    { 
     var cs = ConfigurationManager.ConnectionStrings[_connectionStringName]; 
     if (cs != null) 
     { 
      return cs.ConnectionString; 
     } 
     return null; 
    } 

    public void Write() 
    { 
     Console.WriteLine(_connectionStringName); 
    } 
} 

container.RegisterType<IMetaDataConnectionStringLoader, ConnectionStringLoader>(new InjectionConstructor("MetaConnection")); 
container.RegisterType<IDbConnectionStringLoader, ConnectionStringLoader>(new InjectionConstructor("DbConnection")); 

インターフェースのポイントは、私は私のクラスに異なるインターフェースを注入することができますということで、各実装の正しい接続文字列を取得します。 しかし問題は、最後に登録されたものは前のものを上書きするということです。

var foo = _container.Resolve<IDbConnectionStringLoader>(); 
var bar = _container.Resolve<IMetaDataConnectionStringLoader>(); 
foo.Write(); 
bar.Write(); 

出力は次のとおりです。

DbConnection 
DbConnection 

私は登録順を逆にした場合、出力は二回MetaConnectionになります。今までの私の結論は、最後の登録が前のものを上書きするということです。

public class SomeOtherConnectionStringLoader : ConnectionStringLoader 
{ 
    public ConnectionStringLoaderImpl(string connectionStringName) : base(connectionStringName) 
    { 
    } 
} 

と登録を変更します:私はそれが動作派生クラスに実装を変更する場合は、

container.RegisterType<IMetaDataConnectionStringLoader, ConnectionStringLoader>(new InjectionConstructor("MetaConnection")); 
container.RegisterType<IDbConnectionStringLoader, SomeOtherConnectionStringLoader >(new InjectionConstructor("DbConnection")); 

今、すべてが動作しますが、私は理由を理解していません。私は別の生命探偵を試しましたが、同じ結果を得ました。私はユニティがインターフェイスに基づいて "正しい"注入パラメータでConnectionStringLoaderのインスタンスを作成しようとしていると思っていましたが、ここにいくつかの他のロジックがあるようです。

登録が互いに上書きされる理由を教えてください。

+0

私は、登録名を使用して、次のアプローチに従うことが、より自然な見つけるだろうインターフェイスの? –

+0

良いfind @ YacoubMassad。簡単なテストを作成するためにここにコードを貼り付けた後に追加しました。誤った注射が注射されたことを証明する以外に、実際にはロジックの一部ではありません。私は私の質問を編集します。気づいてくれてありがとう。 – smoksnes

答えて

0

私はUnityに精通していません。しかし、彼らは同じインスタンスにマッピングされているようだ。ですから、ConnectionStringLoader(依存関係ごと)の存続期間を変更する必要があります。

インスタンスを共有しない場合、すべてのものを1つのクラスに入れるのはなぜですか?方法= IDbConnectionStringLoader方法+ IMetaDataConnectionStringLoader方法。

IDbConnectionStringLoaderを解決すると、すでにインスタンスにあるメソッドが使用されません(逆の場合も同じです)。

クレート二つの異なる派生クラスは、この時点では優れている:

抽象クラス:

public abstract class ConnectionStringLoader : IConnectionStringLoader 
{ 
    private readonly string _connectionStringName; 

    public ConnectionStringLoader(string connectionStringName) 
    { 
     _connectionStringName = connectionStringName; 
    } 

    public string Get() 
    { 
     var cs = ConfigurationManager.ConnectionStrings[_connectionStringName]; 
     if (cs != null) 
     { 
      return cs.ConnectionString; 
     } 
     return null; 
    } 

    public void Write() 
    { 
     Console.WriteLine(_connectionStringName); 
    } 
} 

派生クラス:

public sealed class DbConnectionStringLoader : ConnectionStringLoader, IDbConnectionStringLoader 
{ 
    public DbConnectionStringLoader(string connectionStringName):base(connectionStringName) 
    { 

    } 
    //Implement methods here just belongs to IDbConnectionStringLoader 
} 

public sealed class MetaDataConnectionStringLoader : ConnectionStringLoader, IMetaDataConnectionStringLoader 
{ 
    public MetaDataConnectionStringLoader(string connectionStringName):base(connectionStringName) 
    { 

    } 
    //Implement methods here just belongs to IMetaDataConnectionStringLoader 
} 
+0

はい、TransientLifetimeManagerを使用していても、同じインスタンスにマッピングされているようです。 2つの実装を作成するだけで解決できる唯一の方法かもしれませんが、実装が何もしないため、実装を避けたいと思います。 ConnectionStringLoaderとは異なる具体的な実装はありません。 – smoksnes

+0

私は彼らが同じインスタンスにマッピングしているとは思わない。これはConnectionStringLoader ctorを2度呼び出しますが、同じインジェクションパラメータ値(この場合は "DbConnection")を使用します – AksharRoop

0

驚くべきことに、それは二回ConnectionStringLoaderのctorを呼び出していますが、同じで噴射部材。 container.Registrationsを見ると、実際には2つの登録があるため、他のものよりも優先されません。私はRegisterTypeの実装を見ていましたが、私の頭の中には入りませんでした。

あなたの登録の名前を付けることもできますが、それがあなたの全体的な統一ブートストラップ戦略に合っているかどうかは分かりません。

container.RegisterType<IMetaDataConnectionStringLoader, ConnectionStringLoader>("bar", new InjectionConstructor("MetaConnection")); 
container.RegisterType<IDbConnectionStringLoader, ConnectionStringLoader>("foo", new InjectionConstructor("DbConnection")); 

var foo = container.Resolve<IDbConnectionStringLoader>("foo"); 
var bar = container.Resolve<IMetaDataConnectionStringLoader>("bar"); 
1

正直言って、同じクラスでしか実装されていないインターフェイスが2つあるため、インターフェイスを使用している方法が奇妙に見えます。

// If it is a loader the Write method makes no sense (IConnectionStringRepository?) 
public interface IConnectionStringLoader 
{ 
    string Get(); 
    void Write(); 
} 

public class ConnectionStringLoader : IConnectionStringLoader 
{ 
    private readonly string _connectionStringName; 

    public ConnectionStringLoader(string connectionStringName) 
    { 
     _connectionStringName = connectionStringName; 
    } 

    public string Get() 
    { 
     var cs = ConfigurationManager.ConnectionStrings[_connectionStringName]; 
     if (cs != null) 
     { 
      return cs.ConnectionString; 
     } 
     return null; 
    } 

    public void Write() 
    { 
     Console.WriteLine(_connectionStringName); 
    } 
} 

登録:

container.RegisterType<IConnectionStringLoader, ConnectionStringLoader>("Database", new InjectionConstructor("MetaConnection")); 
container.RegisterType<IConnectionStringLoader, ConnectionStringLoader>("Metadata", new InjectionConstructor("DbConnection")); 

解像度:それは一部ではありませんが、あなたが `Write`を呼び出す方法

var foo = _container.Resolve<IConnectionStringLoader>("Database"); 
var bar = _container.Resolve<IConnectionStringLoader>("Metadata"); 
foo.Write(); 
bar.Write(); 
+0

はい、私はそのアプローチも考慮しました。しかし、私の実装では登録名を知る必要があるので、代わりに別のインターフェースを使用しようとしました。可能であれば、登録名の使用を避けてください。または私は間違っていますか? – smoksnes

+0

私たちは通常、コンストラクタにすべてを注入しますので、登録時にすべての作業を行います。クラス内のコンテナを使用することは、通常、一種の反パターンとみなされます(ServiceLocatorの反パターンの検索)。そのことを念頭に置いて、コンテナ依存関係を解決する際に解決される名前を指定する必要のあるコンテナ登録に問題が常に存在します(これはInjectionConstructorに似ています) –