【问题标题】:How to work with Generic type members in extension method?如何在扩展方法中使用泛型类型成员?
【发布时间】:2016-12-07 14:16:32
【问题描述】:

我开始这个扩展方法是为了好玩,但现在我发现自己陷入其中,

其实我想创建一个扩展方法来扩展LINQ,方法如下:

books.In(b => b.Id, 1,2,3,4,5);

它将返回 ID 范围在第二个 params[] 的书籍,

也可以这样:

books.In(b => b.Title, "t1","t2","t3","t4","t5");

我想出的就是这个方法(我今天才知道表达式树!):

 public static List<TEntity> In<TEntity, TMember>(this List<TEntity> list,
            Expression<Func<TEntity, TMember>> identifier, params TMember[] keys)
        {
            Type t = typeof(TEntity); //How to use reflection here?

            List<TEntity> myList = list.Where(m => keys.Contains(m.));
            return myList;
        }

我的问题是如何访问通用类成员:即来自identifier 表达式的m.Id 或m.Title? 我可以使用反射来实现这一点吗?

【问题讨论】:

  • identifier 应该是 Func&lt;TEntity, TMember&gt; 如果您想使用 Enumerable.Where 进行过滤。然后它只是list.Where(m =&gt; keys.Contains(identifier(m)) 尽管您可能希望为键创建一个集合以提高查找效率。
  • 如果打算将此转换为 SQL,那么您应该使用 IQueryable 而不是 List。

标签: c# linq generics reflection extension-methods


【解决方案1】:

应该这样做:

public static IEnumerable<TEnitity> In<TEnitity, TMember>(
    this IEnumerable<TEnitity> source, 
    Func<TEnitity, TMember> projector, IEnumerable<TMember> validCases)
{
    var validSet = new HashSet<TMember>(validCases);
    return source.Where(s => validSet.Contains(projector(s)));
}

或者,严格遵守您提议的签名:

public static IEnumerable<TEntity> In<TEntity, TMember>(
    this IEnumerable<TEntity> source,
    Func<TEntity, TMember> projector, params TMember[] validCases)
{
    var validSet = new HashSet<TMember>(validCases);
    return source.Where(s => validSet.Contains(projector(s)));
}

关于我为什么返回 IEnumerable&lt;T&gt; 而不是 List&lt;T&gt; 的原因是廉价的概括;如果消费者想要返回一个列表,那么他只需要调用ToList,但是如果他可能只想遍历一次枚举,为什么还要让他付出贪婪的枚举费用呢?请记住,LINQ 是 惰性,利用它并​​使其尽可能少地工作。

关于为什么我接受IEnumerable&lt;T&gt; 作为论据,再次廉价概括;为什么只接受一个列表?为什么不是数组、队列、堆栈、集合、迭代器块、哈希集等?

【讨论】:

  • 既然这是一个答案,请您解释一下您的代码,为什么IEnumerable 比List 更好
  • @MohamedAhmed 因为Where 只返回IEnumerable&lt;T&gt;,而不是List&lt;T&gt;。此外:您真的要返回一个可以添加/删除项目的列表吗?
  • 我对这个系列有问题,我看到它们都相似:\
  • 1) 使用更多换行符...水平滚动...:S 2) 您正在多次迭代任意IEnumerable (validCases)。这是危险的,因为它可能不会在每次迭代中产生相同的值,可能会导致副作用等。一遍又一遍地进行线性搜索也很慢。将其放入搜索速度更快的集合中。 3) OP 似乎正在尝试为 EF 创建方法,而不是在内存集合中,如果是这种情况,这些都不会正常工作。
  • @Servy 1) 完成。 2) could 是这里的关键词。 OP 正在谈论使用 params 所以我真的不认为变异枚举是一个问题。性能也是如此,params 意味着一小部分成员,我认为在这种情况下更新HashSet&lt;TMember&gt; 或类似的东西真的不值得。最重要的是,答案并不意味着高性能,它只是为了说明一个可能的解决方案。 3)想知道为什么,在EF上并不是最新的。除非关于validCases 已经说过的话,这怎么可能出错。
猜你喜欢
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多