【问题标题】:Passing LINQ expressions as parameters将 LINQ 表达式作为参数传递
【发布时间】:2017-01-27 00:56:53
【问题描述】:

我设置了一个实体框架类来从 SQL 数据库中读取表,但我不太清楚如何传递 LINQ 表达式来仅过滤某些对象。我知道有一种方法可以构建表达式树并在类中动态地执行此操作,但我似乎无法找到最好的方法。

感谢任何提示。

class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class MyObjectCollection<T> where T : class
{
    private List<T> myInternalCollection = new List<T>();

    MyObjectCollection()
    {
        using (var db = new MyContext()) 
        {
            foreach (T row in db.Set<T>())
            {
                // Enumerate the data, do whatever with it...
                myInternalCollection.Add(row);
            }
        }
    }

    MyObjectCollection(var MyLinqExpression)
    {
        using (var db = new MyContext()) 
        {
            foreach (T row in db.Set<T>().Where.MyLinqExpression()
            {
                // Enumerate the data, do whatever with it...
                myInternalCollection.Add(row);
            }
        }
    }
}

// Works fine:
MyObjectCollection<Customer> allCustomers = new MyObjectCollection<Customer>();

// Would like something like this:
MyObjectCollection<Customer> customersP = new MyObjectCollection<Customer>(c => c.StartsWith("P"));

【问题讨论】:

  • 尝试作为参数Predicate&lt;T&gt;
  • 看看Queryable.Where 方法签名(因为基本上这就是你在问什么)。提示:Expression&lt;Func&lt;T, bool&gt;&gt;

标签: c# entity-framework linq


【解决方案1】:

Linq Where 方法采用 Func&lt;T, bool&gt; 参数,其中 T 是您要应用 Where 方法的 dbSet 对象类型。

所以要让你的代码工作,你可以这样做:

public MyObjectCollection(Func<T, bool> MyLinqExpression)
{
    using (var db = new MyContext())
    {
        foreach (T row in db.Set<T>().Where(MyLinqExpression))
        {
            // Enumerate the data, do whatever with it...
            myInternalCollection.Add(row);
        }
    }
}

更新: 此外,要使用通用集合实现您正在寻找的功能,而不是封装私有 List 对象,您可以从 List 继承,如下所示。因此,如果您希望 MyObjectCollection 像列表一样运行,您可以执行如下所示的操作。

因此,使用上面的代码,您可以更改为:

public class MyObjectCollection<T> : List<T> where T : class
{
    public MyObjectCollection()
    {
        using (var db = new MyContext())
        {
            foreach (T row in db.Set<T>())
            {
                // Enumerate the data, do whatever with it...
                this.Add(row);
            }
        }
    }

    public MyObjectCollection(Func<T, bool> MyLinqExpression)
    {
        using (var db = new MyContext())
        {
            foreach (T row in db.Set<T>().Where(MyLinqExpression))
            {
                // Enumerate the data, do whatever with it...
                this.Add(row);
            }
        }
    }
}

【讨论】:

  • 在这种情况下,返回类型为bool,我建议使用Predicate 而不是Func
  • @Abion47 我一直使用Func 作为 where 方法。我认为 Predicate 会起作用,但是 Func&lt;T, bool&gt; 是 Where 方法的实现方式,并且由于 .NET 3.5 用于这些类型的方法 Func 被推荐而不是 Predicate ......但它是一条细线。这是关于该主题的 Nice Stack 帖子 - Jon Skeet 和 Marc Gravell 也都在这里讨论了这个主题stackoverflow.com/questions/665494/…
  • 我不确定在这个例子中继承是否比聚合更好。通过继承,您可以允许其他人更改 myInternalCollection,这显然不是该类按描述运行所必需的,否则 myInternalCollection 不会被定义为私有的。除了使用此继承限制更改 myInternalCollection 的可能性之外,例如更改为 Dictionary 或更改为其他项目的集合。建议:除非类的使用需要,否则不要让您的数据公开访问
  • @HaraldCoppoolse 是的,很好,你是对的。我根据MyObjectCollection类名的Collection部分做了一个假设。如果需要,最好实现 IEnumerable 进行迭代,或者 ICollection 如果您想公开和控制一些在需要时作用于您的私有列表的功能......但是如果 OP 想要完全隐藏任何暴露到内部 List 对象,那么我的假设完全错误。当我假设时,这会发生很多:)
  • 谢谢大家。超级有帮助。我选择了 Func,效果很好! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
相关资源
最近更新 更多