Unity with factory method who need parameters

99封情书 提交于 2019-12-05 08:18:23

Finally got the solution. It looks like willys one :

container.RegisterType<IApp, App>(
    new InjectionFactory(
        f => App.Create(
            f.Resolve<IOne>(), 
            f.Resolve<ITwo>()
        )
    )
);

Try

container.RegisterType(
    typeof(IApp),
    new InjectionFactory(f => App.Create(
        container.Resolve<IOne>(), 
        container.Resolve<ITwo>())));

Let's say you have this Interface/Class :

public interface IApp { }
public class App : IApp
{
    public App(IOne iOneInstance, ITwo iTwoInstance) { /* Irrelevant */}
}

public interface IOne { }
public class OneA : IOne { }
public class OneB : IOne { }
public interface ITwo { }
public class TwoA : ITwo { }
public class TwoB : ITwo { }

Let's make that your class with the factory method. You wouldn't use both of these, only one version :

// Version One
public class ClassWithFactoryMethodOne
{
    Func<IOne, ITwo, IApp> iAppFactory;
    public ClassWithFactoryMethodOne(Func<IOne, ITwo, IApp> iAppFactory)
    {
        this.iAppFactory = iAppFactory;
    }

    public IApp Create(IOne iOneInstance, ITwo iTwoInstance)
    {
        return this.iAppFactory(iOneInstance, iTwoInstance);
    }
}

// Version Two
public class ClassWithFactoryMethodTwo
{
    Func<string, string, IApp> iAppFactory;
    ClassWithFactoryMethodTwo(Func<string, string, IApp> iAppFactory)
    {
        this.iAppFactory = iAppFactory;
    }

    public IApp Create(string iOneNamedRegistration, string iTwoNamedRegistration)
    {
        return this.iAppFactory(iOneNamedRegistration, iTwoNamedRegistration);
    }
}

If you do the registrations like this, it should work :

class Program
{
    void Main()
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<IOne, OneA>("A");
        container.RegisterType<IOne, OneB>("B");
        container.RegisterType<ITwo, TwoA>("A");
        container.RegisterType<ITwo, TwoB>("B");

        container.RegisterType<Func<IOne, ITwo, IApp>>(
            new InjectionFactory(c =>
                new Func<IOne, ITwo, IApp>((iOne, iTwo) =>
                    c.Resolve<IApp>(
                        new ParameterOverride("iOneInstance", iOne),
                        new ParameterOverride("iTwoInstance", iTwo)))));

        container.RegisterType<Func<string, string, IApp>>(
            new InjectionFactory(c =>
                new Func<string, string, IApp>((iOneNamedRegistration, iTwoNamedRegistration) =>
                    c.Resolve<IApp>(
                        new ParameterOverride("iOneInstance", c.Resolve<IOne>(iOneNamedRegistration)),
                        new ParameterOverride("iTwoInstance", c.Resolve<ITwo>(iTwoNamedRegistration))))));

        // Alternate writing
        container.RegisterType<Func<string, string, IApp>>(
            new InjectionFactory(c =>
                new Func<string, string, IApp>((iOneNamedRegistration, iTwoNamedRegistration) =>
                {
                    IOne iOne = c.Resolve<IOne>(iOneNamedRegistration);
                    ITwo iTwo = c.Resolve<ITwo>(iTwoNamedRegistration);

                    IApp iApp = c.Resolve<IApp>(
                        new ParameterOverride("iOneInstance", iOne),
                        new ParameterOverride("iTwoInstance", iTwo));

                    return iApp;
                })));

        ClassWithFactoryMethodOne versionOne = container.Resolve<ClassWithFactoryMethodOne>();
        // Somewhere you have logic and end up with instances of IOne and ITwo then you :
        IApp iApp1 = versionOne.Create(iOneInstance, iTwoInstance); // This doesn't compile cause you'd need the instances.

        ClassWithFactoryMethodTwo versionTwo = container.Resolve<ClassWithFactoryMethodTwo>();
        IApp iApp2 = versionTwo.Create("A", "B");
    }
}

I think that if I explain the // Alternate Writing I wrote in the Main method, it will clear up some things :

When you use new InjectionFactory, you write a lambda expression that will receive an IUnityContainer as parameter (which I named c.) That expression is used to create the factory itself. In the factory, which has access to c, I then IOne iOne = c.Resolve<IOne>(iOneNamedRegistration);, hence asking the container to resolve an IOne, using the first named registration that the factory will have received. The same thing for ITwo. Then, I ask the container to resolve an IApp for me, overriding the parameter named iOneInstance with the instance of IOne, and same for ITwo.

Oh, and the last lines in the method would be just how you'd actually call the Create methods. The 2nd one would ask the instance of ClassWithFactoryMethodTwo to create an IApp with an IOne that is actually a OneA, and an ITwo that is actually a TwoB.

Anything left unclear?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!