C# 获取通用接口的所有实现类型

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

我试图用下面的代码获取IEntityModelBuilder的所有实现,但它返回一个空集合

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)
来显式转换