Autofac 用不同的参数解析同一个 class 实例

Autofac resolve the same class instance with different parameters

我有一个 Xamarin.Forms 应用程序,我在其中使用 Autofac 进行 DI。

所以我想要的很简单,但我无法做一些看起来很困难的事情。

所以我有一个 class,它有两个构造函数,它们都有一个参数,并且基于某些条件我想解析其中一个。例如,我有一个 class A,我想要的是基于应解决的条件 B 或 C。

例如:

public class A
{

   public A(B bObject)
   {...}

   public A(C cObject)
   {...}
}

但我无法理解该怎么做。我尝试做如下的事情:

报名人数:

 builder.RegisterType<A>().
            UsingConstructor(typeof(C)).
            Named<A>(nameof(C));

 builder.RegisterType<A>().
            UsingConstructor(typeof(B)).
            Named<A>(nameof(B));

正在解决:

DiContainer.ResolveNamed<A>(nameof(B));
DiContainer.ResolveNamed<A>(nameof(C));

注意: 我已经在容器中注册了B和C如下图:

builder.RegisterType<B>();
builder.RegisterType<C>()

我对 AutoFac 有点陌生,我什至不确定这是否正确,我认为这与我注册两次有关,我不确定。

非常感谢任何建议或帮助。

这是一个简单的解决方法:

您可以将 class B 和 C 包装到另一个 class 中,然后在 autofac 中注册:

public class Wrapper {
  public B BObject;
  public C CObject;
}

然后你可以像这样做一点(我不知道解决它的正确方法,因为我目前没有 IDE,但我希望你明白我在这里做什么):

DiContainer.ResolveNamed<A>(new Wrapper(){BObject = Binstance});

另一个解决方案:

您还可以根据需要注册 B 或 C。

如果您希望 class 将用 B 实例化,请在 autofac 上注册 B,然后解析 class。

但是class需要有两个构造函数。一个以 B 作为参数,一个以 C ...

我认为 Autofac 会根据注册的内容解决。

您可以尝试为此使用 Autofac lambda registration 并使用以下代码片段执行注册(此处的c 参数是 IComponentContext 实例)

var builder = new ContainerBuilder();
builder.Register(
    (c, p) =>
    {
        var condition = p.Named<bool>("condition");
        return condition ? new A(c.Resolve<B>()) : new A(c.Resolve<C>());
    });
builder.RegisterType<B>();
builder.RegisterType<C>();

然后通过 passing 一个参数解析 A 到 lambda 表达式。您可以使用 TypedParameter 而不是命名(仅限常量值)或 ResolvedParameter(动态值)

var a = container.Resolve<A>(new NamedParameter("condition", true));

如果您不想显式调用 Resolve,您可以查看委托 factories(例如 Func<T>

我相信你非常接近,你确实需要将 Parameter 定义传递给你的 Resolve

public class B { }
public class C { }
public class A
{
    public A(B bObject){ Console.WriteLine("I am constructor A typeof(B)");}
    public A(C cObject){ Console.WriteLine("I am constructor A typeof(C)");}    
}

void Main()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<A>().UsingConstructor(typeof(B)).Named<A>(nameof(B));
    builder.RegisterType<A>().UsingConstructor(typeof(C)).Named<A>(nameof(C));

    //it doesn't really matter if these are registered as you're using nameof() to identify the objects - that's essentially string
    builder.RegisterType<B>();
    builder.RegisterType<C>();

    var container = builder.Build();

    var a1 = container.ResolveNamed<A>(nameof(B), new TypedParameter(typeof(B), new B()));
    var a2 = container.ResolveNamed<A>(nameof(C), new TypedParameter(typeof(C), new C()));  
}