Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I don't like to answer my own questions, but I was able to somehow solve the problem and I believe the solution is good enough that others may be interested. I looked at Unity's source code and got the basic idea from there. I also read a couple of posts regarding Unity. Here it is:</p> <p>First, I had to create a class that inherited from <code>IBuildPlanPolicy</code>. It is long because I left some supporting classes within the class itself:</p> <pre><code> public class AutomaticFactoryBuilderPolicy : IBuildPlanPolicy { private readonly Dictionary&lt;Type, Type&gt; _callables = new Dictionary&lt;Type, Type&gt; { {typeof(Func&lt;,&gt;), typeof(CallableType&lt;,&gt;)}, {typeof(Func&lt;,,&gt;), typeof(CallableType&lt;,,&gt;)}, {typeof(Func&lt;,,,&gt;), typeof(CallableType&lt;,,,&gt;)}, {typeof(Func&lt;,,,,&gt;), typeof(CallableType&lt;,,,,&gt;)} }; public void BuildUp(IBuilderContext context) { if (context.Existing == null) { var currentContainer = context.NewBuildUp&lt;IUnityContainer&gt;(); 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&lt;T1, TResult&gt; { 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&lt;TResult&gt;(_name, new OrderedParametersOverride(new object[] { p1 })); } } private class CallableType&lt;T1, T2, TResult&gt; { 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&lt;TResult&gt;(_name, new OrderedParametersOverride(new object[] { p1, p2 })); } } private class CallableType&lt;T1, T2, T3, TResult&gt; { 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&lt;TResult&gt;(_name, new OrderedParametersOverride(new object[] { p1, p2, p3 })); } } private class CallableType&lt;T1, T2, T3, T4, TResult&gt; { 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&lt;TResult&gt;(_name, new OrderedParametersResolverOverride(new object[] { p1, p2, p3, p4 })); } } } </code></pre> <p>It is pretty straightforward. The trick is to create one <code>CallableType</code> for each <code>Func</code> I want to handle. It is not as dynamic as I first wanted, but in order to make it more dynamic I believe I would have to deal with either IL or Expression Trees. The way I have it now is good enough for me.</p> <p>Second, Unity handles parameters by name but I had to deal with them by order. That's where OrderedParametersResolverOverride comes into play (this class is used in the code above. Check <code>CallableType</code> classes):</p> <pre><code>public class OrderedParametersResolverOverride : ResolverOverride { private readonly Queue&lt;InjectionParameterValue&gt; _parameterValues; public OrderedParametersResolverOverride(IEnumerable&lt;object&gt; parameterValues) { _parameterValues = new Queue&lt;InjectionParameterValue&gt;(); foreach (var parameterValue in parameterValues) { _parameterValues.Enqueue(InjectionParameterValue.ToParameter(parameterValue)); } } public override IDependencyResolverPolicy GetResolver(IBuilderContext context, Type dependencyType) { if (_parameterValues.Count &lt; 1) return null; var value = _parameterValues.Dequeue(); return value.GetResolverPolicy(dependencyType); } } </code></pre> <p>Those two classes deal with <code>Func</code> creation. The next step is to add that builder to Unity's pipeline. We'll need to create a UnityContainerExtension:</p> <pre><code>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&lt;,&gt;))); Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy), automaticFactoryBuilderPolicy, new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func&lt;,,&gt;))); Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy), automaticFactoryBuilderPolicy, new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func&lt;,,,&gt;))); Context.Policies.Set(typeof(Microsoft.Practices.ObjectBuilder2.IBuildPlanPolicy), automaticFactoryBuilderPolicy, new Microsoft.Practices.ObjectBuilder2.NamedTypeBuildKey(typeof(Func&lt;,,,,&gt;))); } } </code></pre> <p>The last piece is to actually add that class to Unity's pipeline:</p> <pre><code>IUnityContainer container = new UnityContainer(); container.AddExtension(new AutomaticFactoryExtension()); </code></pre> <p>The rest of the registration is standard.</p> <p>Now it is possible to have constructors from <code>Func&lt;&gt;</code> to <code>Fun&lt;,,,,&gt;</code>. The following constructor, for instance, is now handled (assuming it is possible to resolve <code>IFoo</code>):</p> <pre><code>public class Bar { private readonly Func&lt;int, string, IFoo&gt; _fooFactory; public Bar(Func&lt;int, string, IFoo&gt; fooFactory) { _fooFactory = fooFactory; } } </code></pre> <p>Let me know if there are any question.</p> <p>Hope this helps.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload