c# - MemberExpression,从类构建 Expression.Property

标签 c# fluent-nhibernate linq-expressions

下面的表达式将属性 NAME 与值 PETER 进行比较。

            ParameterExpression pe = Expression.Parameter(typeof(T), "x");
            MemberExpression member = Expression.Property(pe, "name");
            ConstantExpression value = Expression.Constant("Peter");
            exp = Expression.Equal(member, value);

如果属性是一个类会怎么样:

            public class Address
            {
                public string Name {get; set;}
            }

那么表达式看起来类似于:

            MemberExpression member = Expression.Property(pe, "Address.Name");
            ConstantExpression value = Expression.Constant("Peter");
            exp = Expression.Equal(member, value);

这会失败,因为成员类型与值类型不匹配。

所以,问题是:如何构建一个可以使用上述类示例工作的表达式??

我在 NHibernate.Linq 查询中使用这个表达式:

        var q = from f in data //of type IQueryable<T>
            select f;
        if (filter != null) //filter of type Expression<Func<T, bool>>
            q = q.Where(filter);
        etc....

谢谢。

Peter 更新:

基于 xanatos 中的代码(下一篇文章),我创建了以下测试以了解其工作原理。它与 xanatos 所做的并没有太大不同,但起初我无法让它工作,所以我决定在一个简单的测试中将它全部编写,然后就成功了。感谢 xanatos:

    [Test]
    public void FilterWithDeepProperties()
    {
        //Arrange
        IGenericGridRepository repository = ObjectFactory.GetInstance<IGenericGridRepository>();

        FilterDescriptor filter = new FilterDescriptor("AgreementId.Name", FilterOperator.IsEqualTo, "a name");
        string[] properties = filter.Member.Split('.');
        ParameterExpression pe = Expression.Parameter(typeof(SampleDomain), "x");

        //Act
        Expression lastMember = pe;
        for (int i = 0; i < properties.Length; i++)
        {
            MemberExpression member = Expression.Property(lastMember, properties[i]);
            lastMember = member;
        }
        ConstantExpression valueExpression = Expression.Constant(filter.Value);
        Expression equalityExpression = Expression.Equal(lastMember, valueExpression);
        Expression<Func<SampleDomain, bool>> where = Expression.Lambda<Func<SampleDomain, bool>>(equalityExpression, pe);
        var result = repository.GetObjects<SampleDomain>(filter: where);

        //Assert
        result.Count().Should().BeGreaterThan(0, "because there are many schedule items equals to " + filter.Value);
    }

最佳答案

你可能想要这样的东西:

public static Expression<Func<TSource, bool>> GetEquality<TSource>(object value, params string[] properties)
{
    ParameterExpression pe = Expression.Parameter(typeof(TSource), "source");

    Expression lastMember = pe;

    for (int i = 0; i < properties.Length; i++)
    {
        MemberExpression member = Expression.Property(lastMember, properties[i]);
        lastMember = member;
    }

    Expression valueExpression = Expression.Constant(value);
    Expression equalityExpression = Expression.Equal(lastMember, valueExpression);
    Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(equalityExpression, pe);
    return lambda;
}

像这样使用它:

Expression exp = GetEquality<Person>("Foo", "Address", "Name");

Foo 是你的 Peter(所以必须比较的值),而 AddressName是属性“链”的名称。例如我正在使用

public class Person
{
    public Address Address { get; set; }
}

public class Address
{
    public string Name { get; set; }
}

所以生成的表达式是

source.Address.Name == "Foo"

如果你想使用像Address.Name这样的东西,你可以使用像这样的方法

Expression exp = GetEquality<Person>("Foo", "Address.Name".Split('.'));

关于c# - MemberExpression,从类构建 Expression.Property,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29075399/

相关文章:

c# - 带复选框的 .NET TreeView 控件

c# - Selenium点击按钮功能

C# MSChart 烛台和移动平均线图表。错误: Formula error - There are not enough data points for the Period

c# - Unity C#,如何从另一个脚本调用一个函数来启动动画?

c# - 流畅的 NHibernate : Index was out of range exception with ReferencesAny mapping

c# - Enumerable.Contains 与 MethodInfo

mvvm - 使用IoC在 View 模型中创建NHibernate存储库

c# - 使用 HQL 查询从所有表而不是一个表中获取数据应该只获取 1 个表的数据

linq - 扩展基于 LINQ 的规范模式以实现包含

c# - 在编译时获取非静态方法的 MethodInfo