24

UnityフレームワークをIoCコンテナーとして使用するプロジェクトに取り組んでいます。私の質問は、プロパティまたはセッターの注入を使用して、オプションの依存関係(この場合はロガー)をいくつかのクラスに注入することに関するものです。

すべてのクラスのコンストラクターをこれらのオプションの依存関係で乱雑にしたくありませんが、Unityでこれを処理するための良い方法を見つけることができません。これを行う方法は、MSDNのドキュメントによると、プロパティに属性を追加することです。

private ILogger logger; 

[Dependency]
public ILogger Logger
{
get { return logger; }
  set { logger = value; }
}

これはとても醜いです。StructureMapでは、次のようにして、特定のタイプのすべてのプロパティを設定できます。

SetAllProperties(policy => policy.OfType<ILog>());

Unityで同様のことができるかどうか誰かが知っていますか?

編集:

Kim Majorは、このアプローチを使用することを提案しています。これは、コードでも実現できます。

一致するすべてのプロパティに対してこれを自動的に行う方法の例に興味があります。

4

8 に答える 8

19

私もそれらの属性が好きではありません

Unity コンテナーのConfigureメソッドを使用して、すべてを行うことができます。

最初にタイプを登録します

unityContainer.RegisterType<MyInterface,MyImpl>(
                     new ContainerControlledLifetimeManager());

複数のコンストラクターがある場合は、これを行う必要があるため、Unity はパラメーターなしのコンストラクターを呼び出します (何も設定されていない場合、Unity は最も太いコンストラクターに移動します)。

unityContainer.Configure<InjectedMembers>()
                            .ConfigureInjectionFor<MyImpl>(
                                new InjectionConstructor()); 

プロパティの依存関係の設定

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                         new InjectionProperty(
                             "SomePropertyName",
                                new ResolvedParameter<MyOtherInterface>()));

メソッドの依存関係の構成

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                        new InjectionMethod(
                            "SomeMethodName",
                            new ResolvedParameter<YetAnotherInterface>()));
于 2009-02-11T12:37:39.667 に答える
16

私は属性を使用することもあまり好きではありませんが.Configure<InjectedMembers>()、特定のプロパティ名と特定の値にバインドされているため、メソッドも好きではありません。私が見つけた最も柔軟な方法は、独自のビルダー戦略を作成することです。

構築中のオブジェクトのプロパティを反復処理し、そのプロパティの型が unity コンテナーに登録されている場合にそのプロパティ値を設定する、この単純なクラスを作成しました。

public class PropertyInjectionBuilderStrategy:BuilderStrategy
{
    private readonly IUnityContainer _unityContainer;

    public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    public override void PreBuildUp(IBuilderContext context)
    {
        if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices"))
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type);

            foreach (PropertyDescriptor property in properties)
            {
                if(_unityContainer.IsRegistered(property.PropertyType)
                   && property.GetValue(context.Existing) == null)
                {
                    property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType));
                }
            }
        }
    }
}

BuilderStrategyを作成して登録しますUnityContainerExtension。次に例を示します。

public class TestAppUnityContainerExtension:UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization);
    }
}

これは、Unity コンテナーに次のように登録されます。

IUnityContainer container = new UnityContainer();
container.AddNewExtension<TestAppUnityContainerExtension>();

これが役に立てば幸いです、
マシュー

于 2011-02-04T15:07:28.400 に答える
7

投稿した元の例は非常に面倒に見えますが、次のような自動実装されたプロパティを使用して、そのコードをクリーンアップすることができます。

[Dependency]
public ILogger Logger { get; set; }
于 2010-11-26T22:59:16.630 に答える
5

Unity 2.1 では、これも同様に機能します。

var container = new UnityContainer()
            .RegisterType<ILogger, Logger>()
            .RegisterType<ISomeInterface, SomeImplementaion>(
                                new InjectionProperty("Logger", new ResolvedParameter<ILogger>()));

SomeImplementaion クラスの注入されたプロパティは

public ILogger Logger { get; set; }
于 2012-03-26T18:41:09.830 に答える
4

あなたはこれを試すことができます:

MyClassのこのコード

[InjectionMethod]
public void Initialize(
                 [Dependency] ILogger logger

そしてそれを次のように呼びます:

unitycontainer.BuildUp<MyClass>(new MyClass());

次に、unityはコンテナからの依存関係を使用してInitializeメソッドを呼び出し、それをMyClassなどのプライベート変数に保存できます...

于 2009-05-23T16:21:05.183 に答える
3

次のウォークスルーは、構成を通じてそれを行う1つの方法を示しています。もちろん、コードを介して配線することもできます。 http://aardvarkblogs.wordpress.com/unity-container-tutorials/10-setter-injection/

于 2009-02-05T08:37:44.730 に答える
1

慣例に基づいた構成については、UnityConfigurationプロジェクトをご覧ください。を使用して複数の実装を検索しているときに問題がありますが、かなりうまく機能しResolveAll<IType>()ます。この質問を参照してください。

container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger());
container.Configure(c => c.Scan(scan =>
                    {
                        scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company")); // Filter out everthing that are not from my assemblies
                        scan.InternalTypes();
                        scan.With<SetAllPropertiesConvention>().OfType<ILogger>();
                    }));
于 2013-04-25T06:37:47.803 に答える
0

Unityコンテナを使用してクラスを注入できます。

たとえば、クラス「MyClass」があり、2 つのインターフェイス「IExample1」と「IExample2」に依存しており、コンストラクターでそれらのパラメーターを定義したくない場合は、以下の手順に従います。

ステップ 1. Unity コンテナーに両方のインターフェースを登録する

IUnityContainer container = new UnityContainer();
container.RegisterType<IExample1,Impl1>();
container.RegisterType<IExample2,Impl2>();
//resolve class MyClass
var myClass = container.Resolve<MyClass>();


ステップ 2.クラスは次のようになります。

public class MyClass
{
     IExample1 ex1;
     IExample2 ex2
     public MyClass(IUnityContainer container)
     {
        /* This unity container is same unity container that we used in step 
           1 to register and resolve classes. So you can use this container to resolve
           all the dependencies. */
       ex1= container.Resolve<IExample1>(); // will give you object of Impl1
       ex2= container.Resolve<IExample2>(); // will give you object of Impl2
     }
}

ステップ 3。このようにして、コンストラクターで定義せずに、任意の数の依存関係を解決できます。

于 2016-09-24T12:24:02.750 に答える