MS Unity:解析自动注册的类型

bar*_*o90 2 c# unity-container

我正在使用MS Unity和"按惯例注册"(自动注册)来注册命名空间中的所有类.代码(见下文)适用于它并返回预期结果

var container = new UnityContainer();
        container.RegisterTypes( AllClasses.FromLoadedAssemblies().Where(
            t => t.Namespace == "DependencyInjectionExample.Test"), 
            WithMappings.FromMatchingInterface, 
            WithName.Default, 
            WithLifetime.ContainerControlled);
Run Code Online (Sandbox Code Playgroud)

结果

集装箱有4个注册

  • IUnityContainer'[默认]'容器
  • TestClass1'[默认]'ContainerControlled
  • TestClass2'[默认]'ContainerControlled
  • TestClass3'[默认]'ContainerControlled

我的问题是我无法弄清楚如何解决它们.我试过了

var allRegistered = container.ResolveAll<ITestable>();
Run Code Online (Sandbox Code Playgroud)

但它不会返回任何内容(所有测试类都实现了ITestable).当我尝试

var singleRegistered = container.Resolve<ITestable>();
Run Code Online (Sandbox Code Playgroud)

我得到'ResolutionFailedException' - "类型ITestable没有可访问的构造函数".我读过这是因为注册的类型没有命名,但在使用自动注册时是不可能的.

我该怎么办才能解决注册类型?

编辑

namespace DependencyInjectionExample.Test
{
 public interface ITestable
 {
    string SaySomething();
 }
}
Run Code Online (Sandbox Code Playgroud)

三个测试类之一.他们都做同样的事情.

namespace DependencyInjectionExample.Test
{
 public class TestClass1 : ITestable
 {
    public TestClass1() { }

    public string SaySomething()
    {
        return "TestClass1 hello";
    }
 }
}
Run Code Online (Sandbox Code Playgroud)

Den*_*rat 9

我仔细研究了RegisterTypes,它接受了Func类型的参数,您可以使用该参数为每个实例提供名称.没有必要创建扩展来实现这一目标.创建属性后,很容易为要在容器中注册的每个实例提供特定名称.

首先创建属性类:

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class UnityNamedInstanceAttribute : Attribute
{
    private readonly string instanceName;

    public UnityNamedInstanceAttribute(string instanceName)
    {
        this.instanceName = instanceName;
    }

    public string InstanceName
    {
        get { return this.instanceName; }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后设置一个类来帮助解析实例的名称:

public static class UnityNamedInstance
{
    public static string AttributeName(Type type)
    {
        var namedAttribute = type
            .GetCustomAttributes(typeof(UnityNamedInstanceAttribute), true)
            .FirstOrDefault()
            as UnityNamedInstanceAttribute;
        return namedAttribute != null ? namedAttribute.InstanceName : null;
    }

    public static string AttributeNameOrDefault(Type type)
    {
        return UnityNamedInstance.AttributeName(type) ?? WithName.Default(type);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用我们创建的属性声明您的测试类:

public interface ITest
{
    void DebugName();
}

[UnityNamedInstance("Test A")]
public class TestA : ITest
{
    #region ITest Members

    public void DebugName()
    {
        Debug.WriteLine("This is TestA");
    }

    #endregion
}
[UnityNamedInstance("Test B")]
public class TestB : ITest
{
    #region ITest Members

    public void DebugName()
    {
        Debug.WriteLine("This is TestB");
    }

    #endregion
}

[UnityNamedInstance("Test C")]
public class TestC : ITest
{
    #region ITest Members

    public void DebugName()
    {
        Debug.WriteLine("This is TestC");
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

并按惯例方法将注册更改为:

        container.RegisterTypes(
            AllClasses.FromLoadedAssemblies().Where(t => t.Namespace == "DependencyInjectionExample.Test"),
            WithMappings.FromAllInterfaces, // This way you have the same instance for each interface the class implements
            UnityNamedInstance.AttributeNameOrDefault, // Use our helper to solve the name of the instance
            WithLifetime.ContainerControlled);
Run Code Online (Sandbox Code Playgroud)

或者您可以避免创建属性和帮助程序并在类名后面命名实例,如下所示:

        container.RegisterTypes(
            AllClasses.FromLoadedAssemblies().Where(t => t.Namespace == "DependencyInjectionExample.Test"),
            WithMappings.FromAllInterfaces,
            WithName.TypeName, // Use the type name for the instances
            WithLifetime.ContainerControlled);
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用在类声明或类名中传递给属性构造函数的名称来访问每个类实例:

        // Access each instance using the name you gave in the attribute
        container.Resolve<ITest>("Test A").DebugName();
        container.Resolve<ITest>("Test B").DebugName();
        container.Resolve<ITest>("Test C").DebugName();
Run Code Online (Sandbox Code Playgroud)

如果您想获得实现特定接口的所有已注册实例:

        foreach (var test in container.Resolve<ITest[]>()) {
            test.DebugName();
        }
Run Code Online (Sandbox Code Playgroud)

要么

        foreach (var test in container.ResolveAll<ITest>()) {
            test.DebugName();
        }
Run Code Online (Sandbox Code Playgroud)

我很想知道这是否符合您的需求.感谢您的反馈!