2011-06-20 9 views
8

内部コンストラクタを持つクラスがあり、それをUnity(2.0)から解決したいと考えています。私は、私は例外UnityContainerと内部コンストラクタ

Exception is: InvalidOperationException - The type MyClass cannot be constructed. 

を持っていないとき

public class MyClass { 
    internal MyClass(IService service) { 
    } 
} 

その後、私は

_container.Resolve<MyClass>(); 

をやっているIServiceが登録され、唯一の問題は、コンストラクタが内部であるということです。 私はこのクラスを公開したいと思っていますが、ファクトリ(実際にはcontainer.Resolve<MyClass>()と呼んでいます)を介してのみ作成できるようにしたいと思います。

Unityに内部コンストラクタが表示されるようにする方法はありますか? InternalsVisibleToなどと同じですか?

+0

なぜあなたはこのctorを公開しませんか?再利用可能なライブラリを作成していますか? – Steven

答えて

8

:-)あなたのコードを難読化するための素晴らしい方法です:

も何をしてうまくいくには、以下のとおりです。この目的のためにユニティをどのように拡張するかについて少しは興味深い情報を見つけました。

まずUnityは内部でIConstructorSelectorPolicyを解決することによってどのコンストラクタを使用するかを選択するようです。ユニティに含まれ、この宝石を含んpublic abstract class ConstructorSelectorPolicyBase<TInjectionConstructorMarkerAttribute>、次のとおりです。

/// <summary> 
/// Choose the constructor to call for the given type. 
/// </summary> 
/// <param name="context">Current build context</param> 
/// <param name="resolverPolicyDestination">The <see cref='IPolicyList'/> to add any 
/// generated resolver objects into.</param> 
/// <returns>The chosen constructor.</returns> 
public SelectedConstructor SelectConstructor(IBuilderContext context, IPolicyList resolverPolicyDestination) 
{ 
    Type typeToConstruct = context.BuildKey.Type; 
    ConstructorInfo ctor = FindInjectionConstructor(typeToConstruct) ?? FindLongestConstructor(typeToConstruct); 
    if (ctor != null) 
    { 
     return CreateSelectedConstructor(context, resolverPolicyDestination, ctor); 
    } 
    return null; 
} 

FindInjectionConstructorと同社は最終的にType.GetConstructors(のみpublicコンストラクタを返すパラメータなしのオーバーロードを、)を呼び出す終わるこのクラスのprivate staticメソッドです。これは、コンストラクタを選択できる独自のコンストラクタセレクタポリシーをUnityが使用するように手配できる場合、あなたは金色であることを示しています。

あり、独自のコンテナ拡張を作り、活用する方法についてgood documentationがあるので、私はそれはあなた自身のCustomConstructorSelectorPolicyを作ることは可能だと想像DefaultUnityConstructorSelectorPolicyの関連部分を含んでいる(抽象基底クラスから派生しない限り、デフォルトであります何か他のものを登録してください)とConstructorSelectorPolicyBase(キーメソッドはvirtualではないので、これは直接的にはうまくいかないかもしれませんが、コードを再利用できます)。

私はそれが適度な量の手間でできると言いますが、最終的な結果はエンジニアリングの観点からはかなり純粋です。

+0

カスタムIConstructorSelectorPolicyの使用例はhttps://msdn.microsoft.com/en-us/library/dn178464(v=pandp.30)です。 aspx – altso

0

Unity 9Iでこれを行うための回避策やハッキングがある可能性がありますが、一般的にUnity(またはIOCコンテナ)によってクラスを管理する場合は、公共のコンストラクターに公開する必要があります。

パブリックコンストラクタを持つクラスを作成し、そのクラスのコンストラクタを内部に保持する抽象ファクトリを作成することもできます。欠点は、あなたの工場はUnityによって管理されますが、クラス自体は管理されません。

+1

"公開コンストラクタで公開する必要があります。 - それは間違っていますが、Unityは公共のコンストラクタを使って内部クラスと完全に動作します。これは、IoCで内部依存関係を管理したい場合です。私がやったのは抽象的な工場です。そして、その中にMyClassのインスタンスを作成したいと思います。新しいMyClass(_container.Resolve ())を使用できますが、手動で行う必要はありません。 – Shaddix

5

ユニティはパブリックコンストラクタだけを見るので、このコンストラクタをパブリックにする必要があります。

私は本当に、このクラスがパブリックになりたい が、私はそれだけで、その場合には 工場

経由で作成可能になりたい、ファクトリを作成:

public class MyClassFactory : IMyClassFactory 
{ 
    private readonly IService service; 

    public MyClassFactory(IService service) 
    { 
     this.service = service; 
    } 

    MyClass IMyClassFactory.CreateNew() 
    { 
     return new MyClass(this.service); 
    } 
} 

そして、登録:

_container.Register<IMyClassFactory, MyClassFactory>(); 

解決:

container.Register<MyClass>(new InjectionFactory(c => 
{ 
    return new MyClass(c.Resolve<IService>()); 
})); 

これは、このコードはMyClassを保持しているアセンブリの内部を見ることができるはず保持アセンブリを動作させるために:あなたはまた、ユニティのInjectionFactoryを使用することができます

_container.Resolve<IMyClassFactory>().CreateNew(); 

。つまり、MyClassアセンブリにはInternalsVisibleToというマークを付ける必要があります。あなたはコンストラクタを公開する必要はありませんが

public static class MyClassFactory 
{ 
    public static MyClass CreateNew(IService service) 
    { 
     return new MyClass(service); 
    } 
} 

container.Register<MyClass>(new InjectionFactory(c => 
{ 
    return MyClassFactory.Create(c.Resolve<IService>()); 
})); 

が、それは私が掘っ

+0

ありがとう、それはほとんど私がやっていることです:)私はちょうどMyClassの依存関係が変更されるたびに、その工場を変更したくないです。だからUnityを介して直接何かを行う方法を探してください – Shaddix

2

ちょうど作り、クラスの内部およびコンストラクタ公共...

  • クラスのコンストラクタ公共の内部

    1. インターフェイスpublic
    2. クラス。
  • 関連する問題