如何在linq中动态创建连接表达式?

时间:2016-09-08 11:10:24

标签: c# linq

(listProductx, listProductx2) => listProductx.ProductName == listProductx2.ProductName && listProductx.ProductCode == listProductx2.ProductCode

在上面的例子中,我想动态设置ProductName和ProductCode。这些是列名;我们可以存储在一个数组或任何地方。我想从数组或列表中动态加入它。

2 个答案:

答案 0 :(得分:2)

假设您将LINQ定位到对象。

实际上Join方法需要3个表达式(funcs) - 外键选择器,内键选择器和结果选择器。由于您想要连接两个相同类型的枚举,因此外键和内键选择器将是同一个。

如果属性的数量不超过7,我们可以使用Tuple<>作为关键字。以下是我们如何动态构建选择器:

static Func<T, object> CreateSelector<T>(IEnumerable<string> propertyNames)
{
    var sourceType = typeof(T);
    var parameter = Expression.Parameter(sourceType, "e");
    var properties = propertyNames.Select(name => Expression.PropertyOrField(parameter, name)).ToArray();
    var selector = Expression.Lambda<Func<T, object>>(
        Expression.Call(typeof(Tuple), "Create", properties.Select(p => p.Type).ToArray(), properties),
        parameter);
    return selector.Compile();
}

然后我们可以创建一个使用它的帮助器方法(将这两个方法放在你选择的顶级公共静态类中):

public static IEnumerable<Tuple<T, T>> Join<T>(this IEnumerable<T> left, IEnumerable<T> right, IEnumerable<string> propertyNames)
{
    var keySelector = CreateSelector<T>(propertyNames);
    return left.Join(right, keySelector, keySelector, Tuple.Create);
}

现在您可以使用以下内容:

class Product
{
    public string ProductName { get; set; }
    public string ProductCode { get; set; }
}

List<Product> list1 = ...;
List<Product> list2 = ...;
var result = list1.Join(list2, new [] { "ProductName", "ProductCode" });

答案 1 :(得分:0)

如果我理解正确,您希望动态构建比较表达式。您可以根据https://msdn.microsoft.com/en-us/library/mt654267.aspx和问题How do I dynamically create an Expression<Func<MyClass, bool>> predicate from Expression<Func<MyClass, string>>?中的文档执行此操作。一般方法是相同的,您只需要以不同方式构建表达式树。