2017-04-13 8 views
0

代理人をコンポーネントとして登録すると、AutowiringParamは解決時にNamedParameterの優先順位を引き受けます。ここでAutofacが2つのコンストラクタの間で解決できない場合は、具体的に具体的に指定してください

は煮詰め例を示します。この場合

public class AParam { } 
public class BParam : IParam { } 

public interface IParam { } 

public interface IAThing { } 
public class AThing : IAThing 
{ 
    public AThing(AParam aParam) { } 
    public AThing(BParam anotherParam) { } 
} 

static void Main(string[] args) 
{ 
    IContainer c = (new ContainerBuilder()).Build(); 

    var anotherBuilder = new ContainerBuilder(); 
    anotherBuilder.RegisterType<AThing>().As<IAThing>().InstancePerDependency(); 
    anotherBuilder.Register((context, parm) => new BParam()).As<BParam>().InstancePerDependency(); 
    anotherBuilder.Update(c); 

    object aParam = new AParam(); 

    //Throws exception, it's unable to decide which constructor to use.... 
    var instance = c.Resolve(typeof(IAThing), new[] {new NamedParameter("aParam", aParam) }); 
} 

、私は正確にNamedParameter「aParam」したいことを指定していますが、AutowiritingParameterはBParamのために記入することができますので、それは分かっていませんどちらのコンストラクタを選択するかは同じパラメータ長です。

私が言及した名前付きパラメータでAutofacが特定のコンストラクタに優先順位を付けるようにするにはどうすればよいですか?私のパラメータが無視されるようにする理由はありません。それは、AutowiringParameterを使用する場合です。

私は "UsingConstructor"を使うことができましたが、BParamがAParamから派生するとすぐに、同じあいまいさに戻ります。 ここでは、指定されたパラメータでコンストラクタを要求しています。 アイデア

編集:

がAutofacだけでエラーなしで、完全にユーザーが指定した名前のパラメータを無視して、あなたは文句を言わない気づくことができますあなたのコンストラクタのデフォルトパラメータを使用!

public class AThing : IAThing 
{ 
    public AThing(AParam aParam) { } 
    public AThing(BParam anotherParam, bool def = true) { } 
} 
+0

あなたの 'Resolve'は' typeof(IAThing) 'を使用しますが、コンストラクタを指定しようとしている具体的なクラス' AThing'ではありません。また、[this](http://docs.autofac.org/en/latest/register/registration.html#selection-of-an-implementation-by-parameter-value)はあなたに何か助けを提供しますか?また、 "インスタンスを作成するデリゲートが宣言され、デリゲートファクトリが使用された場合、よりクリーンで型安全な構文を実現できます"デリゲートとデリゲートファクトリでこれを解決できるかもしれません。 – ErikE

+0

こんにちはErik、 一般的に、私たちは依存関係注入のためにAutofacを使用していますので、解決しようとしているもの(おそらくテストモックアップ)ではなく、名前付きパラメータ "aParam"を持つコンストラクタです。 "AutowiringParameter"を使用してコンストラクタとして "aParam"コンストラクタに同じ "特殊性"(もしあれば)を割り当てる理由がわかりません 以前のバージョンのAutofacではこれまでも使用していました:/そのような無視私は特定のパラメータ名を必要としていました。(同じ問題の型パラメータ結果は同じ問題になります) あなたの返信ありがとう – GettnDer

+1

詳細については、ここで説明しているように、アプリケーションコンポーネントが複数のコンストラクタを持つための反パターンです。 cuttingedge.it/blogs/steven/pivot/entry.php?id=97)。 – Steven

答えて

3

現状で本当に勝てるとは思いません。 が具体的にはより具体的ではありません。パラメータを指定すると、Autofacは、指定されたパラメータをautowiredパラメータとともに取得し、使用可能なすべての情報を考慮して、どのコンストラクタそれは達成することができます。すべてのパラメータが等しい(登録時間(builder.RegisterType<T>().WithParameter(...))、解決時間(scope.Resolve<T>(...))か、autowiredかに関係なく)、どちらのコンストラクタを呼び出す必要がありますか?

パラメータXのような優先度がパラメータYよりも重要な場合は、実際にはかなり複雑になり、トラブルシューティングの難しさを引き起こす可能性があります。解決時間パラメータは登録時パラメータよりも優先されますか?あなたはその行動を無効にできますか?なぜ、なぜそうではないのですか?それは乱雑になる。

これは、このように動作しているため、今後も引き続きそのようになるでしょう。

しかし、あなたはオプションのカップルがあります

オプションを1からUsingConstructor:あなただけのテストで使用するためのコンストラクタは、それはそれがどのように常にかどうBParamを要するものであると指定することができます。

builder.RegisterType<AThing>() 
    .As<IAThing>() 
    .UsingConstructor(typeof(BParam)); 

私はカスタムIConstructorSelectorを作成するための潜在的な能力を示唆するつもりだったが、あなたはそこにインバウンドパラメータを取得していない、を満たすことができることをすでに提供されたパラメータのセットに基づいて、コンストラクタのちょうどリスト。続行するには十分な情報がありません。詳細については、この答えの最後を参照してください。

オプション2 - ラムダ登録:これはおそらく私があなただったらどうなるでしょうか。これはexample in the docs hereに基づいています。これは、実装するためのワンライナーとしてではないのですが、それはあなたが望む効果を取得:

// This is the "default" behavior registration for when 
// no parameters are provided. Note it's named, though, so 
// the actual default registration for IAThing will be the 
// lambda. 
builder.RegisterType<AThing>().Named<IAThing>("default-thing"); 

// This is what will run when you Resolve<IAThing>() 
builder.Register((ctx, p) => { 
    var aorb = p 
    .OfType<NamedParameter>() 
    .Where(n => n.Name == "aParam") 
    .FirstOrDefault(); 
    if (aorb != null) 
    { 
    // You passed the parameter so use it. 
    return new AThing((BParam)aorb.Value); 
    } 
    else 
    { 
    // Use the default reflection-based registration, above. 
    return ctx.ResolveNamed<IAThing>("default-thing", p); 
    } 
}).As<IAThing>(); 

きれいではありませんが、それは仕事を取得します。これらがたくさんある場合は、その一部をデフォルトの登録IDを生成する拡張メソッドにラップし、if/elseロジックを処理します。


は、私はUsingConstructorがより多くのを行うことができますように、より機能コンストラクタセレクターを有効にするために価値があると思います。そのために、私はopened up this issue for youが興味深い拡張であるかどうか確認してください。

+0

NamedParameterで明示的に解決したいので、明らかに "特異性"が高いと思います。もし私がいなければ、私は例外が発生しても驚かないでしょう(あるいは、この場合、唯一のコンストラクタはBParamなのではありません)。 Autofacは既に(より長い長さで)最も特定のコンストラクタを取得しようとしますが、この場合、2つの自動配線パラメータを持つ長さ2のコンストラクタが、私の解決呼び出しで明示的に指定した1つのパラメータで、 CSSセレクタで使用されているものと同じ特異性ルールがあると思っていますが、私はそれが魔法のように動作するとは思っていません。しかし、アイデア – GettnDer

+0

どちらかといえば議論することができると思いますが、私の説明のポイントは、どうしてそれがどういうものなのかを説明することでした。私の答えが助けてくれるといいなあ –

+0

それは残念なことに、アプリケーションは、多くの根本的な獣をサポートし、大きな変更を傷つける獣です。古いバージョンのAutofacが動いていて、誰かがAutofacを更新しました。私はちょうどこのアップデートをサポートしています。 あなたのチケットに返信しました、ありがとうございました – GettnDer

関連する問題