6

我有这样的事情:

public Expression<Func<Message, bool>> FilterData()
{
    switch (this.operatorEnum)
    {
        case FilterParameterOperatorEnum.EqualTo:
            return message => !string.IsNullOrEmpty(message.Body) &&
                              message.Body
                                     .Equals(this.value, StringComparison.InvariantCultureIgnoreCase);

        case FilterParameterOperatorEnum.NotEqualTo:

            return message => !string.IsNullOrEmpty(message.Body) &&
                              !message.Body
                                     .Equals(this.value, StringComparison.InvariantCultureIgnoreCase);

        case FilterParameterOperatorEnum.Contains:

            return message =>
                    !string.IsNullOrEmpty(message.Body) &&
                    message.Body.IndexOf(this.value,
                                   StringComparison.InvariantCultureIgnoreCase) >= 0;

        case FilterParameterOperatorEnum.DoesNotContain:
            return message =>
                    !string.IsNullOrEmpty(message.Body) &&
                    message.Body.IndexOf(this.value,
                                   StringComparison.InvariantCultureIgnoreCase) == -1;


    }
}

如您所见,这是在Message.Body

我现在要对Message类的其他字符串属性执行相同的操作,并且我不想复制所有这些代码。

有没有办法通过以某种方式传递属性来做到这一点?

4

4 回答 4

3

将检索属性值的表达式排除到单独的 lambda 表达式中:

public Expression<Func<Message, bool>> FilterData(Func<Message, string> retrievePropValueFunc)

在您的过滤器表达式中,您可以调用新的 lambda 表达式(仅显示一个作为示例):

return message => !string.IsNullOrEmpty(retrievePropValueFunc(message))
        && retrievePropValueFunc(message)
                .Equals(this.value, StringComparison.InvariantCultureIgnoreCase);

要获取Body属性,请传递message => message.BodyretrievePropValueFunc参数;如您所见,您可以修改它以传递不同的 lambda 表达式以检索其他属性。

于 2013-05-21T09:58:06.203 回答
1

您可以尝试完全手动组合表达式,这将使您能够将属性名称指定为字符串。这不是一个完整的解决方案,并且未经测试,但它可以让您了解我的意思:

var parameter = Expression.Parameter(typeof(Message), "o");
var getname = Expression.Property(parameter, "Body");

var isnullorempty = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, getname));
var compare = Expression.Equal(getname, Expression.Constant("thisvalue"));

var combined = Expression.And(isnullorempty, compare);

var lambda = Expression.Lambda(combined, parameter);

因此,您将更改您的函数以接受“Body”作为参数,然后将最后的 lambda 转换为:

expression<func<Message, bool>>

不过,我可能没有完全正确地创建 lambda 的语法。

于 2013-05-21T11:29:36.787 回答
0

只需更改您的功能以接收属性而不是消息。

或者很难为属性名称传递一个参数并使用反射选择它。

仅针对一个选项进行编辑,而不是针对所有选项进行更改。

    public Func<Message, string, bool> FilterData()
    {
        return (message, propName) =>
        {
            var prop = message.GetType().GetProperty(propName);

            if(prop != null){
                var propValue = (string)prop.GetValue(message,null);
                return !string.IsNullOrEmpty(propValue) && ...;
            }
            return false;
        };

    }
于 2013-05-21T09:55:45.490 回答
0

一种非常快速和肮脏的方法可能是enum一种魔法:

public enum FilterTarget { Body, AnyOtherProp };
public Expression<Func<Message, bool>> FilterData(FilterTarget filterTarget)
{
    string toBeFiltered = string.Empty;

    switch(filterTarget)
    {
        case FilterTarget.Body : 
        { toBeFiltered = message.Body; } break;
        case FilterTarget.AnyOtherProp : 
        { toBeFiltered = message.AnyOtherProp; } break;
        default: 
        { 
            throw new ArgumentException(
                string.Format("Unsupported property {0}", filterTarget.ToString()
            ); 
        } 
    }

    switch (this.operatorEnum)
    {
        case FilterParameterOperatorEnum.EqualTo:
            return message => !string.IsNullOrEmpty(toBeFiltered) &&
                              toBeFiltered.Equals(this.value, StringComparison.InvariantCultureIgnoreCase);

      /* CUT: other cases are similar */
    }
}

您可以使该FilterData方法更加花哨,让它接受params FilterTarget[]从而获得多重过滤功能(在我的脑海中,不包括代码)。

用法:

var aFilterDataResult = FilterData(FilterTarget.Body);    
var anotherFilterDataResult = FilterData(FilterTarget.AnyOtherProp);
...
于 2013-05-21T11:47:47.800 回答