C# 获取通用接口的所有实现类型
我试图用下面的代码获取IEntityModelBuilder的所有实现,但它返回一个空集合C# 获取通用接口的所有实现类型,c#,entity-framework,generics,reflection,C#,Entity Framework,Generics,Reflection,我试图用下面的代码获取IEntityModelBuilder的所有实现,但它返回一个空集合 public class EntityFrameworkDbContext : DbContext { //constructor(s) and entities DbSets... private static IEnumerable<IEntityModelBuilder<IEntity>> _entitymodelBuilders; internal
public class EntityFrameworkDbContext : DbContext
{
//constructor(s) and entities DbSets...
private static IEnumerable<IEntityModelBuilder<IEntity>> _entitymodelBuilders;
internal IEnumerable<IEntityModelBuilder<IEntity>> EntityModelBuilders
{
get
{
if (_entitymodelBuilders == null)
{
var type = typeof(IEntityModelBuilder<IEntity>);
_entitymodelBuilders = Assembly.GetAssembly(type).GetTypes()
.Where(t => type.IsAssignableFrom(t) && t.IsClass)
.Select(t => (IEntityModelBuilder<IEntity>)Activator.CreateInstance(t, new object[0]));
}
return _entitymodelBuilders;
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (var builder in EntityModelBuilders)
builder.Build(modelBuilder);
base.OnModelCreating(modelBuilder);
}
}
internal interface IEntityModelBuilder<TEntity> where TEntity : IEntity
{
void Build(DbModelBuilder modelBuilder);
}
//sample implementation
internal class UserModelBuilder : IEntityModelBuilder<User>
{
public void Build(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.ToTable("users")
.HasKey(e => e.Id);
modelBuilder.Entity<User>()
.Property(e => e.Id)
.HasColumnName("id");
modelBuilder.Entity<User>()
.Property(e => e.Email)
.HasColumnName("email");
//and so on...
}
}
公共类EntityFrameworkBContext:DbContext
{
//构造函数和实体数据库集。。。
私有静态IEnumerable实体模型生成器;
内部IEnumerable EntityModelBuilders
{
得到
{
if(_entitymodelBuilders==null)
{
变量类型=类型(IEntityModelBuilder);
_entitymodelBuilders=Assembly.GetAssembly(类型).GetTypes()
.Where(t=>type.IsAssignableFrom(t)和&t.IsClass)
.Select(t=>(IEntityModelBuilder)Activator.CreateInstance(t,新对象[0]);
}
返回实体模型生成器;
}
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
foreach(EntityModelBuilders中的var生成器)
builder.Build(modelBuilder);
基于模型创建(modelBuilder);
}
}
内部接口IEntityModelBuilder,其中tenty:IEntity
{
void Build(DbModelBuilder-modelBuilder);
}
//示例实现
内部类UserModelBuilder:IEntityModelBuilder
{
公共void生成(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.ToTable(“用户”)
.HasKey(e=>e.Id);
modelBuilder.Entity()
.Property(e=>e.Id)
.姓名(“id”);
modelBuilder.Entity()
.Property(e=>e.Email)
.HasColumnName(“电子邮件”);
//等等。。。
}
}
如果我用
var type = typeof(IEntityModelBuilder<User>);
var type=typeof(IEntityModelBuilder);
获取代码的类型运行良好,并返回预期的UserModelBuilder。如何使用泛型实现这一点?您可以尝试使用泛型
声明:
public interface IEntity { }
public class Entity1 : IEntity { }
public class Entity2 : IEntity { }
public interface IEntityModelBuilder<out T> where T : IEntity { }
public class BaseClass1 : IEntityModelBuilder<Entity1>
{
public BaseClass1(int a) { }
}
public class BaseClass2 : IEntityModelBuilder<Entity2>
{
public BaseClass2(int a) { }
}
List<IEntityModelBuilder<IEntity>> objects = Assembly.GetExecutingAssembly().GetTypes()
.Where(x => x.GetInterfaces().Any(y => y.IsGenericType && && y.Name == "IEntityModelBuilder`1"))
.Select(x => (IEntityModelBuilder<IEntity>)Activator.CreateInstance(x, new object[] { 0 })).ToList();
public接口属性{}
公共类Entity1:Entity{}
公共类Entity2:Entity{}
公共接口IEntityModelBuilder,其中T:IEntity{}
公共类BaseClass1:IEntityModelBuilder
{
公共基本类1(INTA){}
}
公共类BaseClass2:IEntityModelBuilder
{
公共BaseClass2(int a){}
}
用法:
public interface IEntity { }
public class Entity1 : IEntity { }
public class Entity2 : IEntity { }
public interface IEntityModelBuilder<out T> where T : IEntity { }
public class BaseClass1 : IEntityModelBuilder<Entity1>
{
public BaseClass1(int a) { }
}
public class BaseClass2 : IEntityModelBuilder<Entity2>
{
public BaseClass2(int a) { }
}
List<IEntityModelBuilder<IEntity>> objects = Assembly.GetExecutingAssembly().GetTypes()
.Where(x => x.GetInterfaces().Any(y => y.IsGenericType && && y.Name == "IEntityModelBuilder`1"))
.Select(x => (IEntityModelBuilder<IEntity>)Activator.CreateInstance(x, new object[] { 0 })).ToList();
List objects=Assembly.getExecutionGassembly().GetTypes()
.Where(x=>x.GetInterfaces().Any(y=>y.IsGenericType&&&&y.Name==“IEntityModelBuilder`1”))
.Select(x=>(IEntityModelBuilder)Activator.CreateInstance(x,新对象[]{0})).ToList();
尽管Slava的解决方案有效,但由于包含
,因此总体而言并不完全安全。其他接口/类型可能包含您正在搜索的接口的名称。在本例中,假设您有另一个名为IEntityModelBuilderHelper
的接口
此外,只需很少的努力,您就可以将此代码概括为更强大的代码。考虑以下两种方法:
public static IEnumerable<Type> GetAllTypes(Type genericType)
{
if (!genericType.IsGenericTypeDefinition)
throw new ArgumentException("Specified type must be a generic type definition.", nameof(genericType));
return Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.GetInterfaces()
.Any(i => i.IsGenericType &&
i.GetGenericTypeDefinition().Equals(genericType)));
}
公共静态IEnumerable GetAllTypes(类型genericType)
{
如果(!genericType.IsGenericTypeDefinition)
抛出新ArgumentException(“指定的类型必须是泛型类型定义。”,nameof(genericType));
返回Assembly.getExecutionGassembly()
.GetTypes()
.Where(t=>t.GetInterfaces()
.Any(i=>i.IsGenericType&&
i、 GetGenericTypeDefinition().Equals(genericType));
}
以及
公共静态IEnumerable GetAllTypes(类型genericType,参数类型[]genericParameterTypes)
{
如果(!genericType.IsGenericTypeDefinition)
抛出新ArgumentException(“指定的类型必须是泛型类型定义。”,nameof(genericType));
返回Assembly.getExecutionGassembly()
.GetTypes()
.Where(t=>t.GetInterfaces()
.Any(i=>i.IsGenericType&&
i、 GetGenericTypeDefinition().Equals(genericType)&&
i、 GetGenericArguments().Count()==genericParameterTypes.Length&&
i、 GetGenericArguments().Zip(genericParameterTypes,
(f,s)=>s.IsAssignableFrom(f))
.全部(z=>z));
}
前者将为您提供实现提供的泛型类型定义的所有类型,即typeof(MyGenericType)
,对泛型类型参数没有任何约束。后者将执行相同的操作,但使用提供的类型约束
考虑以下类型:
public interface IFoo<T> { }
public interface IEntity { }
public class A : IEntity { }
public class Foo : IFoo<IEntity> { }
public class FooA : IFoo<A> { }
public class FooS : IFoo<string> { }
公共接口IFoo{}
公共接口属性{}
公共类别A:独立性{}
公共类Foo:IFoo{}
公共类FooA:IFoo{}
公共类FooS:IFoo{}
var-types=GetAllTypes(typeof(IFoo))
将返回3种类型:{Foo,FooA,FooS}
而var types=GetAllTypes(typeof(IFoo),typeof(IEntity))
将只返回两种类型:{Foo,FooA}
工作起来很有魅力,但是否可以为Activator.GetInstance返回的每个类型都获取一个实例?越来越近:我如何停止编译器抱怨隐式转换(即_entitymodelBuilders=(IEntityModelBuilder)对象;)?此解决方案是,一般来说,它是脆弱的。从理论上讲,您可能存在名称冲突(IEntityModelBuilderHelper
)并得到错误的结果。如果没有其他方法,我会这么做,但有更安全的解决方案可用。@LucaCelenza,我更新了答案。只有在IEntityModelBuilder
的协变量(out关键字)情况下,您才需要(转换)一点改进,即使用开放的泛型类型typeof(Foo)
而不是封闭的类型typeof(Foo)
来显式转换