C# 在.NET中查看Unity依赖项配置
我们在Unity集装箱内有很多注册。实际上大约有800行 由于Unity没有验证方法,因此在测试应用程序之前,我们引入了一个单元测试来验证配置,该应用程序看起来如下所示,运行良好,并且在配置中发现了许多问题:C# 在.NET中查看Unity依赖项配置,c#,.net,dependency-injection,unity-container,C#,.net,Dependency Injection,Unity Container,我们在Unity集装箱内有很多注册。实际上大约有800行 由于Unity没有验证方法,因此在测试应用程序之前,我们引入了一个单元测试来验证配置,该应用程序看起来如下所示,运行良好,并且在配置中发现了许多问题: IUnityContainer container = UnityContainerBuilder.Build(); foreach (ContainerRegistration mapping in container.Registrations) { container.Res
IUnityContainer container = UnityContainerBuilder.Build();
foreach (ContainerRegistration mapping in container.Registrations)
{
container.Resolve(mapping.RegisteredType, mapping.Name);
}
static void Main(string[] args)
{
Console.WriteLine("Building Unity Container...");
var container = (UnityContainer)UnityContainerBuilder.BuildDirectInUnity();
Console.WriteLine("Listing Registrations...");
FieldInfo policiesField = typeof(UnityContainer).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "policies");
FieldInfo parameterValuesField = typeof(SpecifiedConstructorSelectorPolicy).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "parameterValues");
FieldInfo paramNameField = typeof(ResolvedParameter).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "name");
var policies = (PolicyList)policiesField.GetValue(container);
// build up a dictionary for loop below to use to get the lifetime manager
var typeToRegistration = new Dictionary<Tuple<Type, string>, ContainerRegistration>();
foreach (ContainerRegistration registration in container.Registrations)
{
typeToRegistration.Add(new Tuple<Type, string>(registration.RegisteredType, registration.Name), registration);
}
// now output the list
foreach (ContainerRegistration registration in container.Registrations)
{
Console.WriteLine("{0} to {1}, {2}, {3}",
registration.RegisteredType.Name,
registration.MappedToType.Name,
registration.Name ?? "[default]",
registration.LifetimeManagerType.Name);
// need to check for our InjectionConstructor - I need local = false
IConstructorSelectorPolicy constructorPolicy = policies.Get<IConstructorSelectorPolicy>(
new NamedTypeBuildKey(registration.MappedToType, registration.Name), false);
// and I need SpecifiedConstructorSelectorPolicy as we are not using the default constructor
if (constructorPolicy is SpecifiedConstructorSelectorPolicy)
{
var specifiedConstructorPolicy = constructorPolicy as SpecifiedConstructorSelectorPolicy;
// now output the ResolvedParameters for type, name, lifetime manager
var paramValues = (InjectionParameterValue[])parameterValuesField.GetValue(specifiedConstructorPolicy);
foreach (var param in paramValues)
{
if (param is ResolvedParameter)
{
var resolvedParam = param as ResolvedParameter;
var name = (string)paramNameField.GetValue(resolvedParam);
string lifeTimeManagerName =
typeToRegistration[new Tuple<Type, string>(resolvedParam.ParameterType, name)].LifetimeManagerType.Name;
Console.WriteLine("\t{0}, {1}, {2}", param.ParameterTypeName, name ?? "[default]", lifeTimeManagerName);
}
else
{
Console.WriteLine("\t{0}", param.ParameterTypeName);
}
}
}
}
Console.WriteLine("Complete");
Console.ReadLine();
}
然而,我们有很多类遵循在那里我们使用命名注册。然后使用这些命名注册为其他注册构建InjectionConstructor,例如:
container.RegisterType<IMyType2, Concrete1MyType2>("Concrete1MyType2", new ContainerControlledLifetimeManager());
container.RegisterType<IMyType2, Concrete2MyType2>("Concrete2MyType2", new ContainerControlledLifetimeManager());
container.RegisterType<IMyType1, Concrete1MyType1>(
"Concrete1MyType1",
new ContainerControlledLifetimeManager(),
new InjectionConstructor(
new ResolvedParameter<IMyType2>("Concrete2MyType2")));
container.RegisterType(“Concrete1MyType2”,新的ContainerControlledLifetimeManager());
RegisterType(“Concrete2MyType2”,新的ContainerControlledLifetimeManager());
container.RegisterType(
“混凝土1类型1”,
新建ContainerControlled LifetimeManager(),
新注入构造函数(
新的解析参数(“Concrete2MyType2”);
是否可以通过一些代码访问您在InjectionConstructor中为注册配置的内容?似乎建议您可以
举例如下:
void DisplayContainerRegistrations(IUnityContainer theContainer)
{
string regName, regType, mapTo, lifetime;
Console.WriteLine("Container has {0} Registrations:",
theContainer.Registrations.Count());
foreach (ContainerRegistration item in theContainer.Registrations)
{
regType = item.RegisteredType.Name;
mapTo = item.MappedToType.Name;
regName = item.Name ?? "[default]";
lifetime = item.LifetimeManagerType.Name;
if (mapTo != regType)
{
mapTo = " -> " + mapTo;
}
else
{
mapTo = string.Empty;
}
lifetime = lifetime.Substring(0, lifetime.Length - "LifetimeManager".Length);
Console.WriteLine("+ {0}{1} '{2}' {3}", regType, mapTo, regName, lifetime);
}
}
似乎暗示你可以
举例如下:
void DisplayContainerRegistrations(IUnityContainer theContainer)
{
string regName, regType, mapTo, lifetime;
Console.WriteLine("Container has {0} Registrations:",
theContainer.Registrations.Count());
foreach (ContainerRegistration item in theContainer.Registrations)
{
regType = item.RegisteredType.Name;
mapTo = item.MappedToType.Name;
regName = item.Name ?? "[default]";
lifetime = item.LifetimeManagerType.Name;
if (mapTo != regType)
{
mapTo = " -> " + mapTo;
}
else
{
mapTo = string.Empty;
}
lifetime = lifetime.Substring(0, lifetime.Length - "LifetimeManager".Length);
Console.WriteLine("+ {0}{1} '{2}' {3}", regType, mapTo, regName, lifetime);
}
}
好的,在没有得到太多关于这方面的信息之后,我看了一下Unity的内部,因为我看不到任何公开的方式来做这件事。我提出了以下内容,它使用反射来访问统一的各个部分的私人成员 其主要原因是将瞬态实例注入到单例中有点不匹配。瞬态应该只持续很短的时间,而单例可能会在DI容器的整个生命周期内保持。关于简单喷油器有一些很好的信息。这是尝试获取注入信息的原因之一,因为Unity没有类似于验证的简单注入器 下面是我正在注册的服务接口和类。有3个接口和3个具体实现,但IService2有2个实现
public class Service1 : IService1
{
private readonly IService2 _service2;
private readonly IService3 _service3;
public Service1(IService2 service2, IService3 service3)
{
_service2 = service2;
_service3 = service3;
}
public int DoSomethingForService1()
{
return 1;
}
}
public interface IService1
{
int DoSomethingForService1();
}
public class Service2 : IService2
{
public int DoSomethingForService2()
{
return 1;
}
}
public class Service3 : IService3
{
public int DoSomethingForService3()
{
return 1;
}
}
public interface IService3
{
int DoSomethingForService3();
}
public class Service2_1 : IService2
{
public int DoSomethingForService2()
{
return 1;
}
}
public interface IService2
{
int DoSomethingForService2();
}
现在Unity容器已经构建好了。我们倾向于使用单独的项目,因为我们不希望所有引用都保存在UI中。我们正在使用IService2的2个命名注册
public static class UnityContainerBuilder
{
public static IUnityContainer BuildDirectInUnity()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IService2, Service2>("Service2OneAndOnly", new ContainerControlledLifetimeManager());
container.RegisterType<IService2, Service2_1>("Service2_1", new ContainerControlledLifetimeManager());
container.RegisterType<IService3, Service3>(new ContainerControlledLifetimeManager());
container.RegisterType<IService1, Service1>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(
new ResolvedParameter<IService2>("Service2OneAndOnly"),
new ResolvedParameter<IService3>()));
}
}
公共静态类UnityContainerBuilder
{
公共静态IUnityContainer BuildDirectInUnity()
{
IUnityContainer容器=新的UnityContainer();
RegisterType(“Service2OneAndOnly”,新的ContainerControlledLifetimeManager());
RegisterType(“Service2_1”,新的ContainerControlledLifetimeManager());
RegisterType(新的ContainerControlledLifetimeManager());
container.RegisterType(新ContainerControlled LifetimeManager(),
新注入构造函数(
新的解析参数(“仅服务2”),
新解析参数());
}
}
现在是有趣的部分。这里我们得到了Unity配置:
IUnityContainer container = UnityContainerBuilder.Build();
foreach (ContainerRegistration mapping in container.Registrations)
{
container.Resolve(mapping.RegisteredType, mapping.Name);
}
static void Main(string[] args)
{
Console.WriteLine("Building Unity Container...");
var container = (UnityContainer)UnityContainerBuilder.BuildDirectInUnity();
Console.WriteLine("Listing Registrations...");
FieldInfo policiesField = typeof(UnityContainer).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "policies");
FieldInfo parameterValuesField = typeof(SpecifiedConstructorSelectorPolicy).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "parameterValues");
FieldInfo paramNameField = typeof(ResolvedParameter).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "name");
var policies = (PolicyList)policiesField.GetValue(container);
// build up a dictionary for loop below to use to get the lifetime manager
var typeToRegistration = new Dictionary<Tuple<Type, string>, ContainerRegistration>();
foreach (ContainerRegistration registration in container.Registrations)
{
typeToRegistration.Add(new Tuple<Type, string>(registration.RegisteredType, registration.Name), registration);
}
// now output the list
foreach (ContainerRegistration registration in container.Registrations)
{
Console.WriteLine("{0} to {1}, {2}, {3}",
registration.RegisteredType.Name,
registration.MappedToType.Name,
registration.Name ?? "[default]",
registration.LifetimeManagerType.Name);
// need to check for our InjectionConstructor - I need local = false
IConstructorSelectorPolicy constructorPolicy = policies.Get<IConstructorSelectorPolicy>(
new NamedTypeBuildKey(registration.MappedToType, registration.Name), false);
// and I need SpecifiedConstructorSelectorPolicy as we are not using the default constructor
if (constructorPolicy is SpecifiedConstructorSelectorPolicy)
{
var specifiedConstructorPolicy = constructorPolicy as SpecifiedConstructorSelectorPolicy;
// now output the ResolvedParameters for type, name, lifetime manager
var paramValues = (InjectionParameterValue[])parameterValuesField.GetValue(specifiedConstructorPolicy);
foreach (var param in paramValues)
{
if (param is ResolvedParameter)
{
var resolvedParam = param as ResolvedParameter;
var name = (string)paramNameField.GetValue(resolvedParam);
string lifeTimeManagerName =
typeToRegistration[new Tuple<Type, string>(resolvedParam.ParameterType, name)].LifetimeManagerType.Name;
Console.WriteLine("\t{0}, {1}, {2}", param.ParameterTypeName, name ?? "[default]", lifeTimeManagerName);
}
else
{
Console.WriteLine("\t{0}", param.ParameterTypeName);
}
}
}
}
Console.WriteLine("Complete");
Console.ReadLine();
}
static void Main(字符串[]args)
{
控制台.WriteLine(“构建统一容器…”);
var container=(UnityContainer)UnityContainerBuilder.BuildDirectInUnity();
控制台.WriteLine(“列表注册…”);
FieldInfo policiesField=typeof(UnityContainer).GetFields(
BindingFlags.NonPublic|
BindingFlags.Instance)。首先(f=>f.Name==“策略”);
FieldInfo参数ValuesField=typeof(SpecifiedConstructorSelectorPolicy)。GetFields(
BindingFlags.NonPublic|
BindingFlags.Instance)。首先(f=>f.Name==“parameterValues”);
FieldInfo paramNameField=typeof(ResolvedParameter).GetFields(
BindingFlags.NonPublic|
BindingFlags.Instance)。首先(f=>f.Name==“Name”);
var policies=(PolicyList)policiesField.GetValue(容器);
//为下面的循环建立一个字典,用于获取生命周期管理器
var typeToRegistration=新字典();
foreach(容器注册容器中的注册。注册)
{
typeToRegistration.Add(新元组(registration.RegisteredType,registration.Name),registration);
}
//现在输出列表
foreach(容器注册容器中的注册。注册)
{
WriteLine(“{0}到{1},{2},{3}”,
registration.RegisteredType.Name,
registration.MappedToType.Name,
注册。名称??“[默认]”,
registration.LifetimeManagerType.Name);
//需要检查我们的注入构造函数-我需要local=false
IConstructorSelectorPolicy constructorPolicy=策略。获取(
新的NamedTypeBuildKey(registration.MappedToType,registration.Name),false);
//我需要指定构造函数SelectorPolicy,因为我们不使用默认构造函数
if(指定了constructorPolicy ConstructorSelectorPolicy)
{
var specifiedConstructorPolicy=指定的constructorPolicy作为指定的constructorPolicy;
//现在输出类型、名称和生存期管理器的ResolvedParameters
var paramValues=(InjectionParameterValue[])parameterValuesField.GetValue(specifiedConstructorPolicy);
foreach(paramValues中的var param)
{
if(参数为ResolvedParameter)
{
var resolvedParam=作为ResolvedParameter的参数;
变量名称=(字符串)paramNameField.GetValue(resolvedParam);
字符串lifeTimeManagerName=
typeToRegistration[新元组(resolvedParam.ParameterType,name)]。LifetimeManagerType.name;
WriteLine(“\t{0},{1},{2}”,param.ParameterTypeName,name??“[default]”,lifeTimeManagerName);
}
其他的
{
Console.WriteLine(“\t{0}”,param.ParameterTypeName);
}
}
}
}