使用Autofac解析实现通用接口和抽象类的类列表

问题描述 投票:0回答:1

我正在尝试使用工厂解决策略模式。该工厂生成一个开放的通用接口。它取决于该通用接口的IEnumerable。我可以获得一个非通用的IEnumerable来工作,但是使用泛型我得到一个空列表。

我也可以直接解析该类,但不能解析该列表。

另一个警告是我们可能拥有可能无限的存储库,因此单独注册它们会很痛苦。

我已经尝试过这些方式注册Autofac

var dataAccess = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(dataAccess).AsClosedTypesOf(typeof(Repositories.IRepository<>));

builder.RegisterAssemblyTypes(dataAccess)
                       .Where(t => IsAssignableToGenericType(t, typeof(Repositories.IRepository<>)) && !t.IsAbstract && !t.IsInterface)
                       .AsImplementedInterfaces();

builder.RegisterAssemblyTypes(dataAccess)
                         .Where(t => IsAssignableToGenericType(t, typeof(Repositories.IRepository<>)) && !t.IsAbstract && !t.IsInterface);

public interface IRepository<T> where T : BaseProcessorType
{
    Task Add(T data);
}

public abstract class BaseRepository<T> : IRepository<T> where T : BaseProcessorType
{
    public async Task Add(T data)
    {
        // something
    }
}


public class ActivityRepository : BaseRepository<Activity>, IRepository<Activity>
{
    public ActivityRepository() : base()
    {
    }

    public override async Task Add(Activity data)
    {
        // override
    }
}

然后我想解决

var lol = something.Resolve<IEnumerable<Repositories.IRepository<BaseProcessorType>>>();

但不幸的是,这会返回一个空的IRepositories列表。

c# generics dependency-injection autofac abstract
1个回答
3
投票

让我们忘记Autofac,让我们试着用纯粹的C#来收集它

IEnumerable<IRepository<BaseProcessorType>> l = new IRepository<BaseProcessorType>[] {
                                                       new ActivityRepository() 
                                                };

使用代码示例编译器抛出错误

错误CS0266 - 无法将typeActivityRepository隐式转换为IRepository<BaseProcessorType>。存在显式转换(您是否错过了演员?)

主要错误是ActivityRepository不能转换为IRepository<BaseProcessorType>。为了允许这个演员你必须使用T关键字使out参数协变

public interface IRepository<out T> where T : BaseProcessorType 
{}

但通过这样做你不能有一个T参数的方法

错误CS1961无效方差:类型参数T必须在IRepository<T>.Add(T)上违反有效。 T是协变的。

要理解为什么禁止它,让我们看看这个代码示例:

IRepository<BaseProcessorType> r = new Activity1Repository();
r.Add(new Activity2());

在这个代码示例rActivity1一起工作,但你想添加Activity2Activity1不是Activity2

一种解决方案是不使用T作为类型参数,而是使用BaseProcessorType

public interface IRepository<out T> where T : BaseProcessorType
{
    Task Add(BaseProcessorType data);
}

这样纯C#解决方案就有效了。

要解决IEnumerable<IRepository<BaseProcessorType>>,您需要将您的类型注册为IRepository<BaseProcessorType>

builder.RegisterAssemblyTypes(dataAccess)
       .As(typeof(IRepository<BaseProcessorType>));
© www.soinside.com 2019 - 2024. All rights reserved.