如何注册泛型类型的所有子类型?

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

我正在尝试提炼这个(以及更多):

builder.RegisterType<ZipCodeRepository<ZipCode>>.AsImplementedInterfaces();
builder.RegisterType<MemberRepository<Member>>.AsImplementedInterfaces();
builder.RegisterType<CreditRepository<Credit>>.AsImplementedInterfaces();
builder.RegisterType<DebitRepository<Debit>>.AsImplementedInterfaces();
builder.RegisterType<StateRepository<State>>.AsImplementedInterfaces();
builder.RegisterType<CityRepository<City>>.AsImplementedInterfaces();

...变成这样:

Type[] inheritedTypes;
Type baseType;

baseType = typeof(Repository<Entity>);

inheritedTypes = baseType.Assembly.GetTypes().Where(type =>
{
  return type.BaseType.Name == baseType.Name;
}).ToArray();

builder.RegisterTypes(inheritedTypes).AsImplementedInterfaces();

LINQ 查询有效,返回所有(且仅)继承自

Repository<Entity>
的存储库,但我仍然收到 Autofac 解析错误:

无法解析参数

IZipCodeRepository<ZipCode> ZipCodeRepository

这是我尝试解析存储库的位置:

public class GetZipCodeByCodeQueryHandler : Handler
{
  public GetZipCodeByCodeQueryHandler(string unitOfWork, IZipCodeRepository<ZipCode> zipCodeRepository) : base(unitOfWork)
  {
    _zipCodeRepository = zipCodeRepository;
  }
}

我的目标是自动注册这些,这样我就不必为我在应用程序中创建的每个新实体创建注册(我才刚刚开始,它已经变得过于乏味)。

我尝试了这个答案的变体,这可能可以解决我的情况(如果有的话,也可以松散地解决):

builder
  .RegisterAssemblyTypes(baseType.Assembly)
  .Where(type => type.IsClosedTypeOf(typeof(Repository<>)))
  .As(type => GetIRepositoryType(type)).AsImplementedInterfaces();

...但这没有用。我尝试了

Repository<>
IRepository<>

我也尝试过这个答案。没有运气。同样的错误。

如何在单个表达式中自动注册我的存储库,而不必手动维护不断增长的列表?

--开始编辑--

真正奇怪的是

t
从这个列表中出来的是一个空列表:

var t = new List<Type>();

builder
  .RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
  .Where(type =>
  {
    t.Add(type);
    return type.IsClosedTypeOf(typeof(Repository<>));
  })
  .As(type => this.GetIRepositoryType(type)).AsImplementedInterfaces();

假设我正确地阅读了这篇文章(我认为是这样),Autofac 根本不会尝试评估任何类型。这是怎么算的?

--编辑结束--

这是一个完全可重现的示例:

using System; using System.Linq; using Autofac; public static class Program { public static void Main(string[] Args) { Succeeds(); Fails(); } private static void Succeeds() { IContainer container; ContainerBuilder builder; builder = new ContainerBuilder(); builder.RegisterType<ZipCodeRepository<ZipCode>>.AsImplementedInterfaces(); container = builder.Build; container.Resolve<IZipCodeRepository<ZipCode>>(); } private static void Fails() { Type baseType; Type[] allTypes; IContainer container; ContainerBuilder builder; baseType = typeof(Repository<Entity>); allTypes = baseType.Assembly.GetTypes().ToArray(); Console.WriteLine(allTypes.Contains(typeof(ZipCodeRepository<ZipCode>))); builder = new ContainerBuilder(); builder.RegisterTypes(allTypes).AsImplementedInterfaces(); container = builder.Build; container.Resolve<IZipCodeRepository<ZipCode>>(); } } public interface IRepository<T> where T : Entity { } public abstract class Repository<T> : IRepository<T> where T : Entity { } public abstract class Entity { public int Id { get; set; } } public interface IZipCodeRepository<T> : IRepository<ZipCode> where T : ZipCode { } public class ZipCodeRepository<T> : Repository<ZipCode>, IZipCodeRepository<ZipCode> where T : ZipCode { } public class ZipCode : Entity { }
    
inheritance types reflection autofac
1个回答
0
投票
开放式仿制药与封闭式仿制药似乎存在一些混淆。首先,让我发布使用单元测试的重现版本的稍微更新版本:

public class UnitTest1 { public interface IRepository<T> where T : Entity { } public abstract class Repository<T> : IRepository<T> where T : Entity { } public abstract class Entity { public int Id { get; set; } } public interface IZipCodeRepository<T> : IRepository<ZipCode> where T : ZipCode { } public class ZipCodeRepository<T> : Repository<ZipCode>, IZipCodeRepository<ZipCode> where T : ZipCode { } public class ZipCode : Entity { } [Fact] public void Succeeds() { var builder = new ContainerBuilder(); builder.RegisterType<ZipCodeRepository<ZipCode>>().AsImplementedInterfaces(); var container = builder.Build(); container.Resolve<IZipCodeRepository<ZipCode>>(); } [Fact] public void Fails() { var baseType = typeof(Repository<Entity>); var allTypes = baseType.Assembly.GetTypes().ToArray(); Assert.Contains(typeof(ZipCodeRepository<ZipCode>), allTypes); var builder = new ContainerBuilder(); builder.RegisterTypes(allTypes).AsImplementedInterfaces(); var container = builder.Build(); container.Resolve<IZipCodeRepository<ZipCode>>(); } }
此重现的问题是 

Fails

 单元测试实际上在解析调用之前失败 - 它在这里失败:

// This fails Assert.Contains(typeof(ZipCodeRepository<ZipCode>), allTypes);
原因是你声明的是一个

开放通用ZipCodeRepository<T>

 没有填写的是
T

// This passes - the open generic IS there. Assert.Contains(typeof(ZipCodeRepository<>), allTypes);
这很重要,因为

RegisterAssemblyTypes

不注册开放仿制药。开放泛型(builder.RegisterGeneric
 - 
文档此处)和使用开放泛型处理程序集扫描(此处文档)有不同的注册。

如果我们暂时更新失败的单元测试只是为了注册有问题的一种类型(让我们暂时跳过程序集扫描),我们有:

[Fact] public void Fails() { var baseType = typeof(Repository<Entity>); var allTypes = baseType.Assembly.GetTypes().ToArray(); Assert.Contains(typeof(ZipCodeRepository<>), allTypes); var builder = new ContainerBuilder(); builder.RegisterGeneric(typeof(ZipCodeRepository<>)).AsImplementedInterfaces(); var container = builder.Build(); container.Resolve<IZipCodeRepository<ZipCode>>(); }
到目前为止一切顺利,但现在我们遇到了解决异常:

The service 'IRepository

1[[ZipCode, TestRepro, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' 不是开放的泛型类型定义。`

也就是说,

IRepository<ZipCode>

不是泛型类型定义。我们来看看类和接口:

public interface IZipCodeRepository<T> : IRepository<ZipCode> where T : ZipCode { } public class ZipCodeRepository<T> : Repository<ZipCode>, IZipCodeRepository<ZipCode> where T : ZipCode { }
嗯,其中大部分内容的 

<ZipCode>

 部分看起来像是拼写错误。我们希望类型参数是带有约束的泛型,而不是填充。让我们解决这个问题:

public interface IZipCodeRepository<T> : IRepository<T> where T : ZipCode { } public class ZipCodeRepository<T> : Repository<T>, IZipCodeRepository<T> where T : ZipCode { }

现在当我们运行测试时,它通过了。所以问题是通用声明不正确。

让我们尝试立即通过程序集扫描更新测试:

[Fact] public void DoesNotFailAnymore() { var baseType = typeof(Repository<Entity>); var allTypes = baseType.Assembly.GetTypes().ToArray(); Assert.Contains(typeof(ZipCodeRepository<>), allTypes); var builder = new ContainerBuilder(); builder.RegisterAssemblyOpenGenericTypes(baseType.Assembly) .Where(t => t.GetInterfaces().Any(i => i.Name == typeof(IRepository<>).Name)) .AsImplementedInterfaces(); var container = builder.Build(); container.Resolve<IZipCodeRepository<ZipCode>>(); }

这有效。请注意,存在一些名称比较奇怪的情况,其中开放泛型上的 GetInterfaces()

 返回类型,而 
type(IRepository<>)
 是类型,但是虽然类型相同,但它们并不显示为 
equal 在 LINQ 查询中,所以我做了一个快捷方式并使用了名称。您可以按照自己的喜好更新过滤器。

所以,综上,原代码存在的问题:

    开放仿制药注册不正确。
  • 泛型类型的定义不正确。
© www.soinside.com 2019 - 2024. All rights reserved.