C# LINQ:将 lambda 表达式作为要执行的参数并由方法返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1299534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:52:04  来源:igfitidea点击:

LINQ: Passing lambda expression as parameter to be executed and returned by method

c#linq

提问by Jason Miesionczek

So here is the scenario: i have a series of different repository classes that each can use an isolated data context, or a shared context. In the cases where an isolated context is being used i want to add a method to the base class that will allow me to specify the lambda as the parameter, have that expression be executed by the isolated context of the chosen repository and return an IQueryable result. How would the method signature look, and how to a pass the expression to the context?

所以这里是场景:我有一系列不同的存储库类,每个类都可以使用独立的数据上下文或共享上下文。在使用隔离上下文的情况下,我想向基类添加一个方法,该方法允许我将 lambda 指定为参数,让该表达式由所选存储库的隔离上下文执行并返回 IQueryable 结果. 方法签名看起来如何,以及如何将表达式传递给上下文?

I need the solution to be as generic as possible as any possible model object/table could be used.

我需要解决方案尽可能通用,因为可以使用任何可能的模型对象/表。

Here is basically what i am looking to do:

这基本上是我想要做的:

IAssetRepository repo = new AssetRepository(true); // true indicates isolated context
var results = repo.ExecuteInContext<SomeType>(SomeTable.Where(x => 
                                              x.SomeProp.Equals(SomeValue)));

采纳答案by leppie

Something like this:

像这样的东西:

public IEnumerable<T> ExecuteInContext<T>(
  Expression<Func<T,bool>> predicate)
{
  ... // do your stuff
  //eg
  Table<T> t = GetTable<T>();
  return t.Where(predicate);
}

or

或者

public IEnumerable<T> ExecuteInContext<T>(
   IQueryable<T> src, Expression<Func<T,bool>> predicate)
{
  return src.Where(predicate);
}

Usage:

用法:

var r = repo.ExecuteInContext<SomeType>( 
          x => x.SomeProp.Equals(Somevalue));

or

或者

var r = repo.ExecuteInContext(GetTable<T>(), 
          x => x.SomeProp.Equals(Somevalue));

Assumptions:

假设:

  1. Table can be derived from T, else you will need to pass the source too.
  2. You know how to modify the predicate expression if needed.
  1. 表可以从 T 派生,否则您也需要传递源。
  2. 如果需要,您知道如何修改谓词表达式。

回答by Duncan

Check out PredicateBuilder - http://www.albahari.com/nutshell/predicatebuilder.aspx

查看 PredicateBuilder - http://www.albahari.com/nutshell/predicatebuilder.aspx

This code will package up your where clause as Expression objects which you can pass about.

此代码将您的 where 子句打包为您可以传递的 Expression 对象。

I've implemented the Repository pattern, and my flava is to give it a Fetch(ICriteria) method, which builds up the Where clause depending on the criteria supplied. Simple, but works for me.

我已经实现了 Repository 模式,我的方法是给它一个 Fetch(ICriteria) 方法,它根据提供的标准构建 Where 子句。简单,但对我有用。

回答by Maksym Kozlenko

Here is a complete working sample how to pass LINQ expression as a parameter

这是一个完整的工作示例如何将 LINQ 表达式作为参数传递

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleTest
{
    public class Values
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override string ToString()
        {
            return String.Format("[ X={0} Y={1} ]", X, Y);
        }
    }

    class Program
    {
        static void Main()
        {
            var values = new Values {X = 1, Y = 1};

            // pass parameter to be incremented as linq expression
            IncrementValue(values, v => v.X);
            IncrementValue(values, v => v.X);
            IncrementValue(values, v => v.Y);

            // Output is: [ X=3 Y=2 ]
            Console.Write(values);
        }

        private static void IncrementValue<T>(T obj, Expression<Func<T,int>> property)
        {
            var memberExpression = (MemberExpression)property.Body;
            var propertyInfo = (PropertyInfo)memberExpression.Member;
            // read value with reflection
            var value = (int)propertyInfo.GetValue(obj, null);
            // set value with reflection
            propertyInfo.SetValue(obj, ++value, null);
        }
    }
}