我正在使用MS Unity和“按约定注册”(自动注册)在名称空间中注册所有类。该代码(如下所示)可以正常工作并返回预期结果
var container = new UnityContainer();
container.RegisterTypes( AllClasses.FromLoadedAssemblies().Where(
t => t.Namespace == "DependencyInjectionExample.Test"),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled);
结果
容器有4个注册
IUnityContainer'[默认]'容器
TestClass1'[默认]'ContainerControlled
TestClass2'[默认]'ContainerControlled
TestClass3'[默认]'ContainerControlled
我的问题是我不知道如何解决它们。我尝试过
var allRegistered = container.ResolveAll<ITestable>();
但是它不返回任何内容(所有测试类都实现ITestable)。当我尝试
var singleRegistered = container.Resolve<ITestable>();
我得到一个'ResolutionFailedException'-“类型ITestable没有可访问的构造函数”。我已经读过这是因为未命名已注册的类型,但是使用自动注册时这是不可能的。
如何解决注册的类型?
编辑
namespace DependencyInjectionExample.Test
{
public interface ITestable
{
string SaySomething();
}
}
三种测试类别之一。他们都做同样的事情。
namespace DependencyInjectionExample.Test
{
public class TestClass1 : ITestable
{
public TestClass1() { }
public string SaySomething()
{
return "TestClass1 hello";
}
}
}
最佳答案
我仔细研究了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; }
}
}
然后设置一个类来帮助解析实例的名称:
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);
}
}
使用我们创建的属性声明您的测试课程:
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
}
并按照约定将注册方式更改为:
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);
或者,您可以避免创建属性和帮助程序,并在类名称之后命名实例,如下所示:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().Where(t => t.Namespace == "DependencyInjectionExample.Test"),
WithMappings.FromAllInterfaces,
WithName.TypeName, // Use the type name for the instances
WithLifetime.ContainerControlled);
现在,您可以使用传递给类声明中的属性构造函数的名称或类名称来访问每个类实例:
// 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();
如果要获取实现特定接口的所有注册实例,请执行以下操作:
foreach (var test in container.Resolve<ITest[]>()) {
test.DebugName();
}
要么
foreach (var test in container.ResolveAll<ITest>()) {
test.DebugName();
}
我很想知道这是否符合您的需求。感谢您的反馈!
关于c# - MS Unity:解决自动注册的类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21889596/