LINQ: 把 Lambda 表达式作为参数传递给方法并执行并返回

60
所以这是情境:我有一系列不同的存储库类,每个类可以使用独立的数据上下文或共享上下文。在使用独立上下文的情况下,我希望向基类添加一个方法,用lambda表达式作为参数,并由所选存储库的隔离上下文执行该表达式并返回IQueryable结果。该方法签名应如何设计?如何将表达式传递给上下文?
我需要解决方案尽可能通用,因为任何可能的模型对象/表都可以使用。
以下就是我要做的事情的概述:
IAssetRepository repo = new AssetRepository(true); // true indicates isolated context
var results = repo.ExecuteInContext<SomeType>(SomeTable.Where(x => 
                                              x.SomeProp.Equals(SomeValue)));
3个回答

80

类似这样:

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

或者

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

使用方法:

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

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

假设:

  1. 表格可以从T中派生,否则您需要同时传递源。
  2. 如果需要,您知道如何修改谓词表达式。

尝试您的第一个建议时,我在编译Table<T> t = GetTable<T>();行时遇到错误:必须将T作为引用类型才能将其用作参数。 - Jason Miesionczek
没事了,我搞定了。需要在方法声明的末尾添加“where T:class”。 - Jason Miesionczek
使用LINQ查询语法是否可以实现这个?我无法让 from x in y where predicate select z 正常工作。 - Neil Barnwell

12

这里是一个完整的工作示例,演示如何将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);
        }
    }
}

这个回答顶部的链接已经失效。 - Scott
1
已移除链接。以下是示例代码: - Maksym Kozlenko

6

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

这段代码将把你的where子句打包成表达式对象,你可以随意传递。

我已经实现了仓储模式,并且我的风格是给它一个Fetch(ICriteria)方法,根据提供的条件构建Where子句。简单而有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接