나는 내 자신의 질문에 답하고 싶지 않지만 어떻게 든 문제를 해결할 수 있었고 다른 사람들이 관심을 가질만한 솔루션이라고 생각합니다. 유니티의 소스 코드를보고 거기서 기본적인 아이디어를 얻었습니다. 또한 Unity와 관련하여 몇 가지 게시물을 읽었습니다. 여기에 :
우선, IBuildPlanPolicy
에서 상속받은 클래스를 만들어야했습니다. 클래스 내에서 몇 가지 지원 클래스를 남겨 두었 기 때문에 길었습니다.
public class AutomaticFactoryBuilderPolicy : IBuildPlanPolicy
{
private readonly Dictionary<Type, Type> _callables =
new Dictionary<Type, Type>
{
{typeof(Func<,>), typeof(CallableType<,>)},
{typeof(Func<,,>), typeof(CallableType<,,>)},
{typeof(Func<,,,>), typeof(CallableType<,,,>)},
{typeof(Func<,,,,>), typeof(CallableType<,,,,>)}
};
public void BuildUp(IBuilderContext context)
{
if (context.Existing == null)
{
var currentContainer = context.NewBuildUp<IUnityContainer>();
var buildKey = context.BuildKey;
string nameToBuild = buildKey.Name;
context.Existing = CreateResolver(currentContainer, buildKey.Type, nameToBuild);
}
}
private Delegate CreateResolver(IUnityContainer currentContainer,
Type typeToBuild, string nameToBuild)
{
Type[] delegateTypes = typeToBuild.GetGenericArguments();
Type func = typeToBuild.GetGenericTypeDefinition();
Type callable = _callables[func];
Type callableType = callable.MakeGenericType(delegateTypes);
Type delegateType = func.MakeGenericType(delegateTypes);
MethodInfo resolveMethod = callableType.GetMethod("Resolve");
object callableObject = Activator.CreateInstance(callableType, currentContainer, nameToBuild);
return Delegate.CreateDelegate(delegateType, callableObject, resolveMethod);
}
private class CallableType<T1, TResult>
{
private readonly IUnityContainer _container;
private readonly string _name;
public CallableType(IUnityContainer container, string name)
{
_container = container;
_name = name;
}
public TResult Resolve(T1 p1)
{
return _container.Resolve<TResult>(_name, new OrderedParametersOverride(new object[] { p1 }));
}
}
private class CallableType<T1, T2, TResult>
{
private readonly IUnityContainer _container;
private readonly string _name;
public CallableType(IUnityContainer container, string name)
{
_container = container;
_name = name;
}
public TResult Resolve(T1 p1, T2 p2)
{
return _container.Resolve<TResult>(_name, new OrderedParametersOverride(new object[] { p1, p2 }));
}
}
private class CallableType<T1, T2, T3, TResult>
{
private readonly IUnityContainer _container;
private readonly string _name;
public CallableType(IUnityContainer container, string name)
{
_container = container;
_name = name;
}
public TResult Resolve(T1 p1, T2 p2, T3 p3)
{
return _container.Resolve<TResult>(_name, new OrderedParametersOverride(new object[] { p1, p2, p3 }));
}
}
private class CallableType<T1, T2, T3, T4, TResult>
{
private readonly IUnityContainer _container;
private readonly string _name;
public CallableType(IUnityContainer container, string name)
{
_container = container;
_name = name;
}
public TResult Resolve(T1 p1, T2 p2, T3 p3, T4 p4)
{
return _container.Resolve<TResult>(_name, new OrderedParametersResolverOverride(new object[] { p1, p2, p3, p4 }));
}
}
}
매우 간단합니다. 트릭은 각각 Func
에 대해 하나의 CallableType
을 생성하는 것입니다. 제가 원했던만큼 역동적이지는 않습니다. 그러나 역동적 인 것으로 만들기 위해서 IL이나 Expression Trees 중 하나를 다루어야한다고 생각합니다. 내가 가지고있는 방식은 지금 나를 위해 충분하다.
둘째, Unity는 매개 변수를 이름으로 처리하지만 주문으로 처리해야했습니다. OrderedParametersResolverOverride가 작동하는 곳입니다 (이 클래스는 위의 코드에서 사용됩니다).) CallableType
클래스를 확인하십시오
public class OrderedParametersResolverOverride : ResolverOverride
{
private readonly Queue<InjectionParameterValue> _parameterValues;
public OrderedParametersResolverOverride(IEnumerable<object> parameterValues)
{
_parameterValues = new Queue<InjectionParameterValue>();
foreach (var parameterValue in parameterValues)
{
_parameterValues.Enqueue(InjectionParameterValue.ToParameter(parameterValue));
}
}
public override IDependencyResolverPolicy GetResolver(IBuilderContext context, Type dependencyType)
{
if (_parameterValues.Count < 1)
return null;
var value = _parameterValues.Dequeue();
return value.GetResolverPolicy(dependencyType);
}
}
이 두 클래스는 Func
생성 처리합니다. 다음 단계는 그 빌더를 Unity의 파이프 라인에 추가하는 것입니다. 우리는 UnityContainerExtension을 만들어야합니다 :
public class AutomaticFactoryExtension: UnityContainerExtension
{
protected override void Initialize()
{
var automaticFactoryBuilderPolicy = new AutomaticFactoryBuilderPolicy();
Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy),
automaticFactoryBuilderPolicy,
new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func<,>)));
Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy),
automaticFactoryBuilderPolicy,
new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func<,,>)));
Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy),
automaticFactoryBuilderPolicy,
new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func<,,,>)));
Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy),
automaticFactoryBuilderPolicy,
new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func<,,,,>)));
}
}
마지막 부분은 실제로 유니티의 파이프 라인에 클래스를 추가하는 것입니다
IUnityContainer container = new UnityContainer();
container.AddExtension(new AutomaticFactoryExtension());
등록의 나머지 부분은 표준입니다.
이제 생성자는 Func<>
에서 Fun<,,,,>
까지 가능합니다. 다음 생성자는, 예를 들어, 지금은 (는 IFoo
를 해결 할 수 있습니다 가정) 처리됩니다
public class Bar
{
private readonly Func<int, string, IFoo> _fooFactory;
public Bar(Func<int, string, IFoo> fooFactory)
{
_fooFactory = fooFactory;
}
}
어떤 질문이 있으면 알려주세요.
희망이 도움이됩니다.
어려운 제약 집합입니다 ... 사용자 지정 대리자를 사용하면 매개 변수 이름 일치를 수행하고 매개 변수 재정의를 사용할 수 있습니다 (http://msdn.microsoft.com/en-us/library/ff660920(v=pandp) .20) .aspx # injection_paramoverride) 재정의를 사용하여 컨테이너에 다시 호출하는 함수를 만듭니다. 귀하의 예제에서는 Func에서 인터페이스를 반환하기를 원합니다.이 인터페이스는 인터페이스 구현을 가져올 수 있으므로 솔루션을 더욱 복잡하게 만듭니다. – fsimonazzi
나는 당신의 요점을 fsimonazzi를 참조하십시오. 그러나 그런 식으로 추상 팩토리를 사용하거나 필요한 유형을 등록하는 것이 더 간단합니다. 내가 정말로 이루고자하는 것은 너무 많은 설정없이 Unity의 방법을 유지하는 것입니다. 이상적으로는 컨테이너의 호출을 작성하여 Unity가 나머지를 파악하도록 할 것입니다. – Allan