解决使用Autofac

时间:2019-02-14 20:55:24

标签: c# generics dependency-injection autofac abstract

我正在尝试使用工厂解决策略模式。该工厂生成一个开放的通用接口。它取决于该通用接口的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列表。

1 个答案:

答案 0 :(得分:3)

让我们忘记Autofac,让我们尝试使用纯C#来获取集合。

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

使用代码示例,编译器将引发错误

  

错误CS0266 -无法将类型ActivityRepository隐式转换为IRepository<BaseProcessorType>。存在显式转换(您是否缺少演员表?)

主要错误是ActivityRepository无法转换为IRepository<BaseProcessorType>。为了允许这种类型的转换,您必须使用T关键字使out参数协变

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

但是这样做,您将无法获得带有T参数的方法

  

错误CS1961 :无效的变化:类型参数TIRepository<T>.Add(T)上必须是反有效的。 T是协变的。

要了解为什么禁止使用该代码,请看以下代码示例:

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

在此代码示例中,rActivity1一起使用,但是您要添加Activity2,而Activity1不是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>));