【问题标题】:Make call to generic class nested function调用泛型类嵌套函数
【发布时间】:2017-12-11 06:48:57
【问题描述】:

我有Repository<T>,其中TBaseEntity 类的派生形式。 Repository<T> 具有 IQueryable<T> Table 属性。我需要调用Table 属性中的FirstOrDefault 方法。

到目前为止,我必须列出存储库,但坚持使用反射调用该方法。

private IEnumerable<object> GetEnumerableRepositoryOf<T>(params object[] constructorArgs) where T : class
        {
            List<object> objects = new List<object>();
            foreach (Type type in
                Assembly.GetAssembly(typeof(T)).GetTypes()
                .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(T))))
            {                
                objects.Add(Activator.CreateInstance(typeof(Repository<>).MakeGenericType(type), constructorArgs));
            }
            return objects;
        }

var repoList = GetEnumerableRepositoryOf<BaseEntity>(constructorArgs);
foreach (var repo in repoList)
        {               
            // call FirstOrDefault() here
        }

【问题讨论】:

  • 为什么做的这么奇怪?
  • 当然要从每个存储库中获取第一条记录。 :v
  • 反射是有代价的,实现这个的想法是什么
  • 既然可以返回IEnumerable&lt;T&gt;,为什么还要返回IEnumerable&lt;object&gt;
  • 我的想法是你应该在 Base Repo 中有FirstOrDefault 然后你可以使用T 类型调用

标签: c# entity-framework generics reflection system.reflection


【解决方案1】:

所以您的列表是Repository&lt;X&gt;,其中XT,属性表是IQueryable&lt;X&gt;。由于我们在编译时缺乏X 的类型知识,因此需要反思。

因此,通过使用非泛型接口获取具有反射的属性,然后将转换应用到T,然后执行您的 FirstOrDefault。

你可以这样做:

foreach (var repo in repoList)
{
  var firstOrNull = 
    (repo.GetType().GetProperty("Table").GetValue(repo) as IQueryable)
      .Cast<BaseEntity>().FirstOrDefault();
}

如果使用实体框架(上面不支持这种类型的转换):

foreach (var repo in repoList)
{
  var enumerator = 
    (repo.GetType().GetProperty("Table").GetValue(repo) as IEnumerable)
      .GetEnumerator();

  var firstOrNull = (BaseEntity) (enumerator.MoveNext() ? 
        enumerator.Current : default(BaseEntity));
}

【讨论】:

  • 谢谢您的回答。但是我收到了演员错误LINQ to Entities only supports casting EDM primitive or enumeration types 我也尝试使用object 而不是BaseEntity 但它是一样的。无论如何,我们可以克服它?
  • 你应该考虑在你的问题中提到你使用实体框架,至少使用一个标签。我在答案中添加了一种可能对您有用的替代方法
  • 感谢您的回答,经过一些调整,效果很好。 MoveNext 期间仍然存在 Casting 错误,所以我添加了一些编辑。
  • 我确实看到了 1 个问题,它会在开始时加载所有记录。
  • 确实不应该。你确认了吗? MoveNext 应该只从底层提供者读取第一个返回的记录,除非它的实现被破坏了。
猜你喜欢
  • 2019-05-06
  • 2020-06-29
  • 2013-03-19
  • 1970-01-01
  • 2019-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多