简体   繁体   English

使用反射在方法调用上获取正确的返回值

[英]Getting correct return value on a method call using reflection

I have the following generic method inside my class that works as a repository pattern: 我的类中有以下泛型方法作为存储库模式:

public DbSet<T> GetAll<T>() where T : class
{
  return dbContext.Set<T>();
}

Now, i would like to get a list of all entities in the database that belong to an entity class that implements a specific interface ( IChangeTrackingEntity ). 现在,我想获得数据库中属于实现特定接口( IChangeTrackingEntity )的实体类的所有实体的列表。 So currently there are around 10 specific tables/classes that conform to this, but i don't want to add 10 hardcoded calls to these tables, so I would like to do it using reflection instead (it might also be that the classes that implement this interface change in the future and I don't want to have to remember to change here as well and make the code dependant on each other). 所以目前大约有10个特定的表/类符合这一点,但是我不想为这些表添加10个硬编码调用,所以我想用反射来代替(也可能是实现的类)这个界面将来会发生变化,我也不想记得在这里改变并使代码相互依赖)。

Example of code that works, but that i don't want: 有效的代码示例,但我不想要:

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;

I am quite close, but I can't get the last part to work of casting the result of the Invoke back to the correct type. 我非常接近,但是我无法将最后一部分用于将Invoke的结果转换回正确的类型。 Waht i got currently is this: 我现在得到的是这个:

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;
}

The problem above it that the Invoke call return a object and I need to cast it to basically DbSet<pType> . 上面的问题是Invoke调用返回一个object ,我需要将它DbSet<pType>

In my current code genericMethod.Invoke(repository, null) as DbSet<IChangeTrackingEntity> returns null indicating that I can't cast the return value as I want, so I need the specific return value type and not the interface I think. 在我当前的代码genericMethod.Invoke(repository, null) as DbSet<IChangeTrackingEntity>返回null表示我无法按照自己的意愿转换返回值,因此我需要特定的返回值类型而不是我认为的接口。

Any idea of how to accomplish this? 知道怎么做到这一点?

Try casting to IEnumerable<IChangeTrackingEntity> . 尝试转换为IEnumerable<IChangeTrackingEntity> This should work due to co/contravariance. 这应该由于共同/逆转而起作用。

I don't know much about this specific issue, but you seem to be casting from DbSet<T> where T : IChangeTrackingEntity to DbSet<IChangeTrackingEntity> . 我对这个具体问题了解不多,但您似乎是从DbSet<T> where T : IChangeTrackingEntity进行投射, DbSet<T> where T : IChangeTrackingEntityDbSet<IChangeTrackingEntity> This is called covariance or contravariance (I always get confused between them...) and it only works if DbSet<> is an interface. 这被称为协方差或逆变(我总是在它们之间混淆......)它只有在DbSet<>是一个接口时才有效。 So, casting won't work here. 所以,铸造在这里不起作用。 Use an equivalent interface if you can, or make a generic method that accepts DbSet where T: IChangeTrackingEntity and returns DbSet<IChangeTrackingEntity> somehow. 如果可以的话,使用等效的接口,或者创建一个接受DbSet的泛型方法,其中T: IChangeTrackingEntity并以某种方式返回DbSet<IChangeTrackingEntity> I'll try to work out how to do that, and post an answer, if no one has answered before me (unlikely on this site :P) 如果没有人在我面前回答,我会尝试找出如何做到这一点并发布答案(不太可能在本网站上发布:P)

I'm thinking you need to see this question : 我想你需要看到这个问题

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM