否定表达

时间:2015-02-10 20:56:37

标签: c# linq expression

我有一个返回表达式的函数,我传入一个字段和一个值。我有返回StartsWith的函数,但我想返回NOT StartsWith

private Expression<Func<T, bool>> GenerateFieldDoesNotStartsWithExpression<T>(string fieldName, string value) {
    var parameter = Expression.Parameter(typeof(T), "i");
    var fieldAccess = Expression.PropertyOrField(parameter, fieldName);
    MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
    var passedValue = Expression.Constant(value, typeof(string));
    var body = Expression.Call(fieldAccess, method, passedValue);
    var expr = Expression.Lambda<Func<T, bool>>(body, parameter);
    return expr;
}

返回i.[fieldName].StartsWith(value),但我正在寻找 !i.[fieldName].StartsWith(value)

我尝试了一些设置,例如设置parameter = !i和第二个参数设置为i,但接下来我得到了参数&#39;!i&#39;没有约束&#34;。

我试过搞乱Expression.Not,似乎无法让它发挥作用。

1 个答案:

答案 0 :(得分:3)

使用Expression.Call

围绕Expression.Not
var body = Expression.Not(Expression.Call(fieldAccess, method, passedValue));

您的密码:

    private Expression<Func<T, bool>> GenerateFieldDoesNotStartsWithExpression<T>(string fieldName, string value)
    {
        var parameter = Expression.Parameter(typeof(T), "i");
        var fieldAccess = Expression.PropertyOrField(parameter, fieldName);
        MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
        var passedValue = Expression.Constant(value, typeof(string));
        // Wrapped Expression.Call with Expression.Not
        var body = Expression.Not(Expression.Call(fieldAccess, method, passedValue));
        var expr = Expression.Lambda<Func<T, bool>>(body, parameter);
        return expr;
    }

测试代码:

[TestFixture]
public class ExpressNotTests
{
    [Test]
    public void GenerateFieldDoesNotStartsWithExpression_DoesNotStartWith_True()
    {
        var a = new TestClass() {TestString = "Not"};

        var exp = GenerateFieldDoesNotStartsWithExpression<TestClass>("TestString", "Test");

        var res = exp.Compile()(a);

        res.Should().BeTrue();
    }

    [Test]
    public void GenerateFieldDoesNotStartsWithExpression_DoesStartsWith_False()
    {
        var a = new TestClass() {TestString = "TestString"};

        var exp = GenerateFieldDoesNotStartsWithExpression<TestClass>("TestString", "Test");

        var res = exp.Compile()(a);

        res.Should().BeFalse();
    }


    private class TestClass
    {
        public string TestString { get; set; }
    }
}