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

我也不喜欢这些属性

您可以使用统一容器的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

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.

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 BuilderStrategy by creating a UnityContainerExtension. Here is an example:

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:

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

Hope this helps,
Matthew

于 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());

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

于 2009-05-23T16:21:05.183 回答
3

以下演练显示了通过配置完成此操作的一种方法。您当然也可以通过代码连接它。 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

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

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

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

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 回答