OK,在這個沒有得到很多信息後,我看了一下團結內部,因爲我看不到這樣做的任何公開方式。我提出了以下使用Reflection來訪問Unity各個部分的私有成員。
這樣做的主要原因是將瞬態實例注入到單例中是有點不匹配的。瞬間應該只能持續很短的時間,而單身可能在DI容器的整個生命週期中保持不變。關於簡單注射器here有一些很好的信息。這是嘗試獲取注入信息的原因之一,因爲Unity沒有像簡單注入器那樣的驗證。
所以,這裏是我正在註冊的服務接口和類。有3個接口和3個具體實現,但有2個實現的IService2除外。
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中。我們正在使用2個名爲IService2的註冊。
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>()));
}
}
現在有趣的部分。在這裏,我們得到了統一配置:
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();
}
這樣做的缺點是,它是純粹基於反射黑客攻擊,它不支持InjectionFactory在那裏你可以配置類型的新實例。
@Nikolia - 我遇到過那一個。它基本上顯示了你有什麼類型的映射和終身管理器。我想知道我用InjectionConstructors配置了什麼。這篇文章沒有涉及。 – Andez