如何使用 autofac 通过字符串解析 class 与第 3 方通用接口

How can I resolve a class with 3rd party generic interface by string using autofac

在 autofac 中注册了不同的 classes,它们具有相同的通用接口,但使用不同的 class 模型。我需要的是在不知道 class 模型的情况下用字符串解析 class 。我不确定它是否可以轻松实现。请有任何建议。

我正在使用控制台应用程序,但我不知道 class 模型,因为我们收到了一个字符串。我已经在开始 class 中注册了所有 class,但我想在不知道 class 模型的情况下解析 class。我不想使用 if else 来表示 if string == "something" then resolve this else if resolve this。我正在寻找最佳实践。

public TestModel1 { }
public TestModel2 { }

public interface ICalculator<string, T> {}
public Impl1: ICalculator<string, TestModel1> {}
public Impl2: ICalculator<string, TestModel2> {}

在 Autofac 中我注册为:

builder.Register<Impl1>.As<ICalculator<string, TestModel1>>();
builder.Register<Impl2>.As<ICalculator<string, TestModel2>>();

在控制台应用程序中,我想执行如下操作: container.Resolve 按字符串而不是像

if (...) {
class = container.resolve<ICalculator<string, TestModel1>>()
} else {
class = container.resolve<ICalculator<string, TestModel2>>()
}

我希望能够在控制台应用程序中执行类似的操作:

var class = container.resolve<ICalculator>("pass string");

AFAIK 你只能解决你注册的问题。所以你不能从 ICalculator<string, TestModel2> 得到 ICalculator 因为这是两个非常不同的接口。

使用Named Services。你可以这样做:

假设:

public class Impl1 : ICalculator<string, TestModel1> {}
public class Impl2 : ICalculator<string, TestModel1> {}
// Notice these are the same ---------------------^
// If these need to be different use #2 (Below)

注册:

builder.Register<Impl1>.Named<ICalculator<string, TestModel1>>("pass string1");
builder.Register<Impl2>.Named<ICalculator<string, TestModel1>>("pass string2");
// Notice these are the same ------------------------------^

通过以下方式解决:

var r = container.resolve<ICalculator<string, TestModel1>>("pass string2) 
// = Impl2

或 2.

首先创建一个基础接口:

public interface ICalculator {}
public interface ICalculator<T1, T2> : ICalcuator;

public class Impl1 : ICalculator<string, TestModel1> {}
public class Impl2 : ICalculator<string, TestModel2> {}

注册:

builder.Register<Impl1>.Named<ICalculator>("pass string1");
builder.Register<Impl2>.Named<ICalculator>("pass string2");

已通过

解决
var r = container.resolve<ICalculator>("pass string2) 
// = Impl2

如果您的控制台应用程序(或真实应用程序)非常复杂,您真的应该考虑使用作用域来帮助控制对象的生命周期:

builder
  .Register<Impl1>
  .Named<ICalculator<string, TestModel1>>("pass string1")
  .InstancePerLifetimeScope();
builder
  .Register<Impl2>
  .Named<ICalculator<string, TestModel1>>("pass string2")
  .InstancePerLifetimeScope();

然后

using (scope1 = container.BeginLifetimeScope())
{
  var r = scope1.Resolve<ICalculator>("pass string1");
  // r would be disposed if it implemented IDisposable
  // before scope1 is `Disposed()`
}

However, the problem I face is that the interface is coming from a library developed by another team.

在那种情况下,您可以尝试注册泛型,并让 DI 在解析时而不是在实现期间知道泛型类型:

// @nuget: Autofac

using System;
using Autofac;

public class Program
{
    private static IContainer _Container;
    public static void Main()
    {
        var builder = new ContainerBuilder();

        builder
            .RegisterGeneric(typeof (Impl1<, >))
            .Named("pass string1", typeof (Calculator3rdParty<, >))
            .InstancePerLifetimeScope();

        builder
            .RegisterGeneric(typeof (Impl2<, >))
            .Named("pass string2", typeof (Calculator3rdParty<, >))
            .InstancePerLifetimeScope();

        _Container = builder.Build();

        using (var scope = _Container.BeginLifetimeScope())
        {
            var c3p = scope
                .ResolveNamed<Calculator3rdParty<string, Model1>>("pass string2");
            // specify type at resolve ----------^

            Console.WriteLine(c3p.GetType());
        }
    }
}

public interface Calculator3rdParty<T1, T2>{}

public class Model1{}

public class Model2{}

public class Impl1<T1, T2> : Calculator3rdParty<T1, T2>{}

public class Impl2<T1, T2> : Calculator3rdParty<T1, T2>{}

输出:

Impl2`2[System.String,Model1]

DotNetFiddle Example