创建通用基础实例 class

Creating instances of generic base class

我正在使用 Dapper.FluentMap 库,并尝试设置我的映射 classes 的自动注册。为此,我需要为每个 class 映射调用 FluentMapConfiguration.AddMap<T>(EntityBase<T>)

我可以这样做:

public class TypeAMap : EntityMap<TypeA> {}
public class TypeBMap : EntityMap<TypeB> {}
public class TypeCMap : EntityMap<TypeC> {}

public void Register(FluentMapConfiguration configuration)
{
  configuration.AddMap(new TypeAMap());
  configuration.AddMap(new TypeBMap());
  configuration.AddMap(new TypeCMap());
  // I have a hundred of these, you can see where I'm going...
}

当您忘记注册地图并想知道为什么您的数据无法正确加载时,这显然是一个问题。所以关于自动注册的一些反思:

public void Register(FluentMapConfiguration configuration)
{
  var maps = GetType().Assembly.GetExportedTypes().Where(t =>
      !t.IsAbstract &&
      !t.IsInterface &&
      t.BaseType is { IsGenericType: true } &&
      t.BaseType.GetGenericTypeDefinition() == typeof(EntityMap<>)
    ).ToArray();

    foreach (var map in maps)
    {
      var baseType = typeof(EntityMap<>);
      var typeArguments = map.BaseType.GetGenericArguments();
      var genericType = baseType.MakeGenericType(typeArguments);
      var instance = Activator.CreateInstance(genericType);

      configuration.AddMap((dynamic) instance);
    }
}

但是当它到达对 Activator.CreateInstance 的调用时,它失败了,出现 MissingMethodExceptionCannot create abstract class。看起来它正在尝试创建 EntityBase<TypeA> 而不是 TypeAMap 的实例,并且由于 EntityBase<T> 是抽象的 class,我收到了错误。那么我该如何正确构建我的实例呢?

Where 调用过滤掉程序集中的类型,仅包括非抽象类型、非接口类型以及 EntityMap<anything> 的直接子class 类型。所以 maps 包含类型 TypeAMapTypeBMapTypeCMap

然后对于其中的每一个,您的代码获取其基础 class 并尝试实例化 that。查看for循环中的注释代码:

// suppose "map" is typeof(TypeAMap)

var baseType = typeof(EntityMap<>);
// typeArguments would be an array containing typeof(TypeA) only.
var typeArguments = map.BaseType.GetGenericArguments();
// genericType would be typeof(EntityMap<TypeA>)
var genericType = baseType.MakeGenericType(typeArguments);
// now you try to instantiate a EntityMap<TypeA>, and fails, because EntityMap<TypeA> is abstract
var instance = Activator.CreateInstance(genericType);

因为你想做 new TypeAMap()new TypeBMap() 等的反射版本,而且我们知道 maps 包含你想实例化的那些类型,你可以这样做:

foreach (var map in maps) 
{
    var instance = Activator.CreateInstance(map);
    configuration.AddMap((dynamic) instance);
}

您根本不需要关心 EntityMap 的泛型类型参数。当动态绑定器尝试推断 AddMap.

的类型参数时,它将弄清楚这一点