Autofac - 通过工厂方法解决

时间:2018-04-01 05:50:17

标签: c# autofac ioc-container interceptor factory-method

我似乎无法在Autofac中绕过这种情况:

  • 我的业务逻辑需要IFinal类型的对象。
  • 实现类Final有几个业务逻辑不知道的依赖项,但可以通过IoCContainer直接解析。
  • Final还有其他依赖项,只有业务逻辑在运行时才知道。
  • 我希望能够在IFinal上使用拦截器,因此应该通过IFinal注册并解决类Final。

所以我试图为IFinal创建一个工厂,但我似乎无法使解决方案正确。

示例代码:

    public static void Main(string[] args)
    {
        ContainerBuilder builder = new ContainerBuilder();

        builder.RegisterType<Dependency>().As<IDependency>();

        builder.RegisterType<Final>().As<IFinal>();

        // this fails because context c is not available at the time finalObjectFactoryMethod is used
        builder.Register<Factory>((c,p)=>{
            var dependency = c.Resolve<IDependency>();
            Func<int, IFinal> finalObjectFactoryMethod =
                rta => c.Resolve<IFinal>(
                    new TypedParameter(typeof(IDependency), dependency),
                    new TypedParameter(typeof(int), rta)
                );
            return new Factory(finalObjectFactoryMethod);
        }).As<IFactory>();

        // this works but doesn't use the resolve mechanism for IFinal
        /*
        builder.Register<Factory>((c,p)=>{
            var dependency = c.Resolve<IDependency>();
            Func<int, IFinal> finalObjectFactoryMethod = rta => new Final(dependency, rta);
            return new Factory(finalObjectFactoryMethod);
        }).As<IFactory>();
        */

        IContainer container = builder.Build();


        IFactory factory = container.Resolve<IFactory>();
        IFinal final = factory.GetFinalObject(42);
    }
}


public interface IDependency{}

public class Dependency: IDependency{}


public interface IFinal
{
    void Test();
}

public class Final: IFinal
{
    public Final(IDependency dependency, int runtimeArgument){}

    public void Test(){}
}


public interface IFactory
{
    IFinal GetFinalObject(int runtimeArgument);
}

public class Factory: IFactory
{
    readonly Func<int, IFinal> _finalObjectFactoryMethod;

    public Factory(Func<int, IFinal> finalObjectFactoryMethod)
    {
        _finalObjectFactoryMethod = finalObjectFactoryMethod;
    }

    public IFinal GetFinalObject(int runtimeArgument)
    {
        return _finalObjectFactoryMethod(runtimeArgument);
    }
}

Google和Autofac文档对此无法帮助我 不知何故,我的大脑似乎有一个结,也许我只是试图使用错误的模式 我很确定有一个解决方案,但我无法找到它。

2 个答案:

答案 0 :(得分:1)

很好的例子“问正确的问题,你会找到正确的答案” 我一直试图让这个工作2天,我在这里发布问题后1小时,我自己找到了答案:P

这是包括Interceptor的工作代码:

class MainClass
{
    public static void Main(string[] args)
    {
        ContainerBuilder builder = new ContainerBuilder();

        builder.RegisterType<Interceptor>();

        builder.RegisterType<Dependency>().As<IDependency>();

        builder.RegisterType<Final>().As<IFinal>();

        builder.Register<IFinal>((c, p) =>
        {
            IDependency dependency = c.Resolve<IDependency>();
            int runtimeArgument = p.Named<int>("runtimeArgument");
            return new Final(dependency, runtimeArgument);
        }).As<IFinal>()
       .EnableInterfaceInterceptors()
       .InterceptedBy(typeof(Interceptor));

        builder.Register<Factory>((c,p)=>{
            Factory.FactoryMethod finalObjectFactoryMethod = c.Resolve<Factory.FactoryMethod>();
            return new Factory(finalObjectFactoryMethod);
        }).As<IFactory>()
       .EnableInterfaceInterceptors()
       .InterceptedBy(typeof(Interceptor));

        IContainer container = builder.Build();


        IFactory factory = container.Resolve<IFactory>();
        IFinal final = factory.GetFinalObject(42);
        final.Test();
    }
}


public interface IDependency{}

public class Dependency: IDependency{}


public interface IFinal
{
    void Test();
}

public class Final: IFinal
{
    public Final(IDependency dependency, int runtimeArgument){}

    public void Test(){}
}


public interface IFactory
{
    IFinal GetFinalObject(int runtimeArgument);
}

public class Factory: IFactory
{
    public delegate IFinal FactoryMethod(int runtimeArgument);

    readonly FactoryMethod _finalObjectFactoryMethod;

    public Factory(FactoryMethod finalObjectFactoryMethod)
    {
        _finalObjectFactoryMethod = finalObjectFactoryMethod;
    }

    public IFinal GetFinalObject(int runtimeArgument)
    {
        return _finalObjectFactoryMethod(runtimeArgument);
    }
}

public class Interceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"call {invocation.Method.Name}");
        invocation.Proceed();
        Console.WriteLine($"return from {invocation.Method.Name}");
    }
}

拦截器现在将其写入控制台:

call GetFinalObject
return from GetFinalObject  
call Test  
return from Test  

也许这可以帮助其他人。

答案 1 :(得分:1)

您必须将工厂 delegate添加到Final

public class Final : IFinal
{
    public delegate IFinal Factory(int runtimeArgument);

    public Final(IDependency dependency, int runtimeArgument) { }

    public void Test() { }
}

Autofac非常聪明,可以填充其他参数,因此您的工厂委托只能在运行时指定参数,而其他参数可以通过 magic 解析。

然后注册类型:

    builder
        .RegisterType<Final>()
        .As<IFinal>();

以下是完整的示例:

public static void Main(string[] args)
{
    ContainerBuilder builder = new ContainerBuilder();

    builder
        .RegisterType<Dependency>()
        .As<IDependency>();

    builder
        .RegisterType<Final>()
        .As<IFinal>();

    using(var container = builder.Build())
    using (var scope = container.BeginLifetimeScope())
    {

        var finalFactory = scope.Resolve<Final.Factory>();
        IFinal final = finalFactory(42);
    }
}

根本不需要Factory课程。委托可以直接从scope解析,也可以使用与任何其他依赖相同的方式,并由Autofac注入。只是juse Final.Factory作为你的依赖。

文档在Delegate Factories

中描述了这种技术