我的类中有以下泛型方法,用作存储库模式:
public DbSet<T> GetAll<T>() where T : class
{
return dbContext.Set<T>();
}
现在,我想获得数据库中属于实现特定接口(IChangeTrackingEntity
)的实体类的所有实体的列表。所以目前大约有10个特定的表/类符合这一点,但是我不想为这些表添加10个硬编码调用,所以我想用反射来代替(也可能是实现的类)这个界面将来会发生变化,我不想记得在这里改变并使代码相互依赖)。
有效的代码示例,但我不想要:
var result = new List<IChangeTrackingEntity>();
using ( var repository = new DbRepository())
{
result.AddRange( repository.GetAll<FirstTypeThatImplementsInterface>() );
result.AddRange( repository.GetAll<SecondTypeThatImplementsInterface>() );
result.AddRange( repository.GetAll<ThirdTypeThatImplementsInterface>() );
result.AddRange( repository.GetAll<FourthTypeThatImplementsInterface>() );
result.AddRange( repository.GetAll<FifthTypeThatImplementsInterface>() );
}
return result;
我非常接近,但我无法完成将Invoke
的结果转换回正确类型的最后一部分。我现在得到的是:
var result = new List<IChangeTrackingEntity>();
var method = typeof (DbRepository).GetMethod("GetAll");
using ( var repository = new DbRepository())
{
foreach (var p in typeof(AnchorDbContext).GetProperties())
{
if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
{
var pType = p.PropertyType.GetGenericArguments()[0];
if (pType.GetInterface("IChangeTrackingEntity") != null)
{
var genericMethod = method.MakeGenericMethod(new[] {pType});
result.AddRange(genericMethod.Invoke(repository, null) as DbSet<IChangeTrackingEntity>);
}
}
}
return result;
}
上面的问题是,Invoke调用返回object
,我需要将其强制转换为DbSet<pType>
。
在我当前的代码genericMethod.Invoke(repository, null) as DbSet<IChangeTrackingEntity>
中返回null
,表示我无法按需要转换返回值,因此我需要特定的返回值类型而不是我认为的接口。
知道如何实现这个目标吗?
答案 0 :(得分:3)
尝试转换为IEnumerable<IChangeTrackingEntity>
。这应该是由于共同/逆转而起作用。
答案 1 :(得分:1)
我对这个具体问题了解不多,但您似乎是从DbSet<T> where T : IChangeTrackingEntity
投射到DbSet<IChangeTrackingEntity>
。这被称为协方差或逆变(我总是在它们之间混淆......)并且它仅在DbSet<>
是接口时才有效。所以,铸造在这里不起作用。如果可以,请使用等效接口,或者创建一个接受DbSet的通用方法,其中T:IChangeTrackingEntity
并以某种方式返回DbSet<IChangeTrackingEntity>
。如果没有人在我面前回答(我不太可能在本网站上发表:P),我会尝试找出如何做到这一点并发布答案。
答案 2 :(得分:0)
我想你需要看this question:
MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);