向接收 ArgumentException 的 Autofac 注册 Keyed 实现(类型 X 不可分配给服务 Y)

Register Keyed implementation with Autofac receiving an ArgumentException (Type X not assignable to service Y)

我正在使用 Autofac Keyed 选项注册一些具体类型。在我向类型和接口添加通用参数之前,这一切似乎都运行良好。

我的注册是这样的:

builder.RegisterType<Customer.DataAccess.Database.StoreElasticConnectionManagerByCompany>();
builder.RegisterType<Customer.DataAccess.Database.StoreElasticConnectionManagerByStore>();
builder.RegisterType<Customer.DataAccess.Database.StoreElasticConnectionManager>();
builder.RegisterType<Customer.DataAccess.Database.DatabaseManagement>().As<IDatabaseManagement>();

builder.RegisterType<ConnectionManagerFactory<Customer.DataAccess.Database.StoreElasticConnectionManagerByStore>>()
    .Keyed<IConnectionManagerFactory<IConnectionManager>>(DatabaseConnectionShardingTypes.StoreDatabaseByStoreId);
builder.RegisterType<ConnectionManagerFactory<Customer.DataAccess.Database.StoreElasticConnectionManagerByCompany>>()
    .Keyed<IConnectionManagerFactory<IConnectionManager>>(DatabaseConnectionShardingTypes.StoreDatabaseByCompanyId);

builder.RegisterType<DatabaseManagement>().As<IDatabaseManagement>().SingleInstance();

具体的类型和接口是这样实现的:

/*The factories*/
public interface IConnectionManagerFactory<T>
        where T : IConnectionManager 
{}

public class ConnectionManagerFactory<T> : IConnectionManagerFactory<T>
        where T : IConnectionManager
{}
/*The Connection Manager*/
public interface IConnectionManager
{}
public abstract class StoreElasticConnectionManager : IConnectionManager
{}
public class StoreElasticConnectionManagerByStore : StoreElasticConnectionManager
{}

当我尝试 运行 我的代码时(当注册正在执行时)我收到以下错误:

An unhandled exception of type 'System.ArgumentException' occurred in Autofac.dll

Additional information: The type 'Customer.DataAccess.Database.ConnectionManagerFactory1[Customer.DataAccess.Database.StoreElasticConnectionManagerByStore]' is not assignable to service 'StoreDatabaseByStoreId (Customer.DataAccess.Database.IConnectionManagerFactory1[[Customer.DataAccess.Database.IConnectionManager, Customer.DataAccess.Database, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]])'.

这可能是因为我已经将通用参数添加到 ConnectionManagerFactory,因为在我这样做之前它就起作用了。

我试过添加以下内容:

builder.RegisterGeneric(typeof(Customer.DataAccess.Database.ConnectionManagerFactory<>))
                                                    .As(typeof(IConnectionManagerFactory<>));

但这似乎并没有解决问题。

关于如何进行的任何建议?

编辑

针对 nemesv 的问题,这是有效的代码,我没有使用泛型

builder.RegisterType<Customer.DataAccess.Database.StoreElasticConnectionManagerByCompany>();
                builder.RegisterType<Customer.DataAccess.Database.StoreElasticConnectionManagerByStore>();
                builder.RegisterType<Customer.DataAccess.Database.StoreElasticConnectionManager>();

                builder.RegisterType<ConnectionManagerFactory<Customer.DataAccess.Database.StoreElasticConnectionManagerByStore>>()
                                .Keyed<IConnectionManagerFactory>(DatabaseConnectionShardingTypes.StoreDatabaseByStoreId);
                builder.RegisterType<ConnectionManagerFactory<Customer.DataAccess.Database.StoreElasticConnectionManagerByCompany>>()
                                .Keyed<IConnectionManagerFactory>(DatabaseConnectionShardingTypes.StoreDatabaseByCompanyId);

如您所见,接口 IConnectionManagerFactory 不再通用。

具体 ConnectionManagerFactory 现在看起来像这样:

public class ConnectionManagerFactory<T> : IConnectionManagerFactory
        where T : IConnectionManager

DatabaseConnectionShardingTypes 是一个简单的枚举。

我现在通过稍微更改代码并不再使用泛型解决了我的问题,但我仍然想知道我在上面的示例中做错了什么。

您正在尝试将 ConnectionManagerFactory<StoreElasticConnectionManagerByStore> 转换为 IConnectionManagerFactory<IConnectionManager>

您必须指定您的接口是协变的以允许此类强制转换,您可以使用 out 修饰符(有关详细信息,请参阅 "out T" vs. "T" in Generics

public interface IConnectionManagerFactory<out T>
        where T : IConnectionManager
{ }

如果您尝试以下代码行,您将遇到编译错误:

ConnectionManagerFactory<StoreElasticConnectionManagerByStore>  c = null;
IConnectionManagerFactory<IConnectionManager> i = (ConnectionManagerFactory<StoreElasticConnectionManagerByStore>)c; 

Cannot implicitly convert type 'ConnectionManagerFactory' to 'IConnectionManagerFactory'. An explicit conversion exists (are you missing a cast?)

添加 out 修饰符意味着您的界面不能在方法参数中接受 T

public interface IConnectionManagerFactory<out T>
        where T : IConnectionManager
{
    void Do1(T t); // not valid 
    T Do2();       // valid
}

如果您的 IConnectionManagerFactory<T> 不是协变的,您将不得不更改代码,例如拆分接口