在 Autofac 中,RegisterAssemblyOpenGenericTypes 和 RegisterAssemblyTypes with AsClosedTypesOf 有什么区别?

In Autofac, what is the difference between RegisterAssemblyOpenGenericTypes and RegisterAssemblyTypes with AsClosedTypesOf?

我有一个由多个具体实现的通用接口 class。例如:

public interface IMyInterface<T> {}
internal class Impl1 : IMyInterface<int> {}
internal class Impl2 : IMyInterface<float> {}

我想自动注册 IMyInterface<T> 的所有实现,以便我可以解析类型 T 支持的特定实现(在本例中,intfloat).例如:

class TheConsumer
{
  // `impl` should resolve to `Impl1`
  public TheConsumer(IMyInterface<int> impl) {}
}

根据我从 this github issue and the documentation 收集到的信息,似乎有两种机制可以做到这一点:

var builder = new ContainerBuilder();

// Mechanism 1
builder.RegisterAssemblyOpenGenericTypes(typeof(Startup).Assembly)
    .AssignableTo(typeof(IMyInterface<>))
    .AsImplementedInterfaces();

// Mechanism 2
builder.RegisterAssemblyTypes(typeof(Startup).Assembly)
    .AsClosedTypesOf(typeof(IMyInterface<>))
    .AsImplementedInterfaces();

我只成功测试了上面显示的第二种机制。第一个我推测是一样的;但它可能不是。总的来说,我真的很困惑 Autofac 是如何处理“泛型”的。文档也没有提及 RegisterAssemblyOpenGenericTypes,这无济于事。所以这是我的问题:

What is an "open" and "closed" generic (terminology from the Autofac documentation)?

开放泛型具有未定义的类型参数(例如 List<T>)。然而,封闭的泛型具有定义的类型参数(例如 List<int>)。

  • What is the functional difference between the two versions above?

目前,您的两个实现都是 IMyInterface<T>:

的“封闭式”通用实现
internal class Impl1 : IMyInterface<int> { }
internal class Impl2 : IMyInterface<float> { }

当您将 RegisterAssemblyOpenGenericTypes(“机制 1”)与这些一起使用时,您会得到一个异常,即在解析 TheConsumerIMyInterface<int> 未知。当您将 RegisterAssemblyTypes 与这些封闭的通用实现一起使用时,Impl1 在解析 TheConsumer.

时会按预期传递

RegisterAssemblyOpenGenericTypes 的用法可以通过稍微扩展您的示例来说明。如果您添加 IMyInterface<T> 的另一个实现,例如:

internal class Impl3<T> : IMyInterface<T> { }

您知道 IMyInterface<T> 有一个“开放”的通用实现。因此,当您返回 RegisterAssemblyOpenGenericTypes(“机制 1”)并尝试解析 TheConsumer 时,它起作用了,并且传入了 Impl3<int>

In what case would you choose one or the other?

RegisterAssemblyTypes 与您当前拥有的“封闭”泛型类型一起使用,IMyInterface<T> 的用户将只能解析使用该类型专门实现的接口(例如 IMyInterface<int>Impl1 实现)。当您只想要在 IMyInterface<T>.

中使用的一组特定类型参数时,这可能是理想的选择

当您实际上并不关心 IMyInterface<T> 中使用的类型参数是什么时,使用 RegisterAssemblyOpenGenericTypes 会很有用。这本质上只是允许更灵活地使用 IMyInterface<T>,这是您可能想要也可能不想要的东西。