.net Unity中没有属性的Setter /属性注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/515028/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 11:11:41  来源:igfitidea点击:

Setter / property injection in Unity without attributes

.netinversion-of-controlunity-container

提问by LittleBoyLost

I am working on a project where the Unity framework is used as the IoC container. My question relates to injecting an optional dependency (in this case a logger) into several classes using property- or setter injection.

我正在开发一个使用 Unity 框架作为 IoC 容器的项目。我的问题涉及使用属性或 setter 注入将可选依赖项(在本例中为记录器)注入多个类。

I do not want to clutter the constructors of all my classes with these optional dependencies, but I cannot find a good way to handle this in Unity. The way you would do this is, according to the MSDN documentation, by adding an attribute to the property:

我不想用这些可选的依赖项来混淆我所有类的构造函数,但我找不到在 Unity 中处理这个问题的好方法。根据MSDN 文档,您可以通过向属性添加属性来执行此操作:

private ILogger logger; 

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

I find this very ugly. In StructureMapone could do the following to set all properties of a given type:

我觉得这非常丑陋。在StructureMap 中,可以执行以下操作来设置给定类型的所有属性:

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

Does anyone know if it is possible to do something similar in Unity?

有谁知道是否可以在 Unity 中做类似的事情?

Edit:

编辑:

Kim Major suggests using this approachwhich can also be achieved through code.

Kim Major 建议使用这种也可以通过代码实现的方法

I would be interested in examples of how to do this automatically for all matching properties.

我会对如何为所有匹配的属性自动执行此操作的示例感兴趣。

回答by t3mujin

I don't like those attributes also

我也不喜欢这些属性

You can do all using the Configuremethod of the unity container:

您可以使用统一容器的Configure方法完成所有操作:

First register the type

首先注册类型

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

If you have multiple constructors you'll have to do this so Unity invokes the parameterless constructor (if none set Unity will go for the fattest one)

如果您有多个构造函数,则必须执行此操作,以便 Unity 调用无参数构造函数(如果未设置,则 Unity 将使用最胖的构造函数)

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

Setting property dependency

设置属性依赖

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

Configuring method dependency

配置方法依赖

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                        new InjectionMethod(
                            "SomeMethodName",
                            new ResolvedParameter<YetAnotherInterface>()));

回答by Matthew

I am also not a big fan of using attributes but I also don't like the .Configure<InjectedMembers>()method because you're bound to a specific property name and specific value. The way I've found that gives you the most flexibility is to create your own builder strategy.

我也不喜欢使用属性,但我也不喜欢该.Configure<InjectedMembers>()方法,因为您绑定到特定的属性名称和特定值。我发现为您提供最大灵活性的方法是创建您自己的构建器策略。

I created this simple class that iterates the properties of an object being built up and sets its property values if the type of that property has been registered with the unity container.

我创建了这个简单的类,它迭代正在构建的对象的属性,并在该属性的类型已注册到统一容器时设置其属性值。

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));
                }
            }
        }
    }
}

You register your BuilderStrategyby creating a UnityContainerExtension. Here is an example:

BuilderStrategy通过创建一个UnityContainerExtension. 下面是一个例子:

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

That gets registered with the Unity container as such:

这会在 Unity 容器中注册,如下所示:

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

Hope this helps,
Matthew

希望这会有所帮助,
马修

回答by RamonH

The original example you posted does look very cumbersome, but you can use auto-implemented properties like this to help clean that code up:

您发布的原始示例确实看起来很麻烦,但是您可以使用这样的自动实现的属性来帮助清理该代码:

[Dependency]
public ILogger Logger { get; set; }

回答by Oleksandr Lytvyn

With Unity 2.1 this would work as well:

使用 Unity 2.1 这也可以:

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

The injected property of SomeImplementaion class is just

SomeImplementaion 类的注入属性只是

public ILogger Logger { get; set; }

回答by Johan Leino

You could try this:

你可以试试这个:

this code in MyClass

MyClass 中的这段代码

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

and then calling it by:

然后通过以下方式调用它:

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

unity will then call Initialize method with the dependency from the container and then u can save it in a private variable in MyClass or something...

unity 然后将使用来自容器的依赖项调用 Initialize 方法,然后您可以将其保存在 MyClass 或其他东西的私有变量中...

回答by Kim Major

The following walkthrough shows one way of doing it through configuration. You can of course wire it through code as well. http://aardvarkblogs.wordpress.com/unity-container-tutorials/10-setter-injection/

以下演练展示了通过配置执行此操作的一种方法。您当然也可以通过代码连接它。 http://aardvarkblogs.wordpress.com/unity-container-tutorials/10-setter-injection/

回答by NooBody

Have a look at the UnityConfigurationproject for convention-based configuration. It works pretty well, though i have an issue while looking up multiple implementations using ResolveAll<IType>(). See this Question.

查看基于约定的配置的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>();
                    }));

回答by Manish Kumawat

You can inject your class with unity container.

您可以使用统一容器注入您的课程。

for example if you have a class "MyClass" and you have dependency on two interface "IExample1" and "IExample2" and you don't want to define parameter for them in constructor , then follow below steps

例如,如果您有一个类“MyClass”并且您依赖于两个接口“IExample1”和“IExample2”,并且您不想在构造函数中为它们定义参数,那么请按照以下步骤操作

Step 1.Register both the interfaces in unity container

步骤 1.在统一容器中注册两个接口

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


Step 2.Your class should look like this


第 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
     }
}

Step 3. In this way you can resolve any number of dependencies without defining them in constructor.

第 3 步。通过这种方式,您可以解析任意数量的依赖项,而无需在构造函数中定义它们。