Unity 与需要参数的工厂方法

Unity with factory method who need parameters

我想用需要参数的工厂方法在 Unity 容器中注册一个类型。这些参数要统一解决,但只能在运行时解决。

工厂方法代码:

public static IApp Create(IOne, ITwo) {...}

注册码:

container.RegisterType(typeof(IApp), new InjectionFactory(f => App.Create(???, ???)));

我需要什么来替换'???' ?

更多信息:

我的 Unity 配置分两个阶段进行。第一阶段(申请开始),我注册了我所有的对象,除了一个:

container.RegisterType<IOne, One>();
container.RegisterType<ITwo, Two>();
container.RegisterType<IApp, App>();
// ...

第二阶段(用户正在登录),我只是注册了一个上下文对象的实例,该对象在我所有 类(OneTwoApp, ...) :

var childContainer = container.CreateChildContainer();
childContainer.RegisterInstance<AppEnvironment>(new AppEnvironment(userName));

这是我没有使用 InjectionFactory 的代码。它工作正常。现在,我必须多次注册我的 IApp 接口,每次都调用不同的静态方法。静态方法示例:

public static IApp Create(IOne one, ITwo two, AppEnvironment env) 
{
    _one = one;
    _two = two;
    _env = env;
}

如果我注册这个 IApp 这个代码:

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

那我的环境变量没有设置。

但是如果我注册我的 env 实例(只是为了测试目的,我不能这样做),它会起作用。

尝试

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

假设你有这个 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 { }

让我们用工厂方法把它变成你的 class。 你不会同时使用这两个,只使用一个版本:

// 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);
    }
}

如果您这样注册,应该可以:

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");
    }
}

我想如果我解释一下我在Main方法中写的// Alternate Writing,它会澄清一些事情:

当您使用 new InjectionFactory 时,您编写了一个 lambda 表达式,它将接收一个 IUnityContainer 作为参数(我将其命名为 c。)该表达式用于创建工厂本身.在可以访问 c 的工厂中,我然后 IOne iOne = c.Resolve<IOne>(iOneNamedRegistration);,因此要求 容器 解析 IOne,使用第一个 named工厂将收到的注册。 ITwo 也是如此。然后,我要求 容器 为我解析一个 IApp,用 IOne 的实例覆盖名为 iOneInstance 的参数,ITwo.

哦,该方法的最后几行就是您实际调用 Create 方法的方式。第二个会要求 ClassWithFactoryMethodTwo 的实例创建一个 IApp,其中 IOne 实际上是 OneA,而 ITwo 实际上是 TwoB.

还有什么不清楚的吗?

终于找到解决办法了。看起来像 willys one :

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