返回表达式<>使用各种类属性

时间:2013-05-21 09:46:32

标签: c# .net linq lambda

我有这样的事情:

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 个答案:

答案 0 :(得分:3)

将检索属性值的表达式Eclude到单独的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.Body传递给retrievePropValueFunc参数;如您所见,您可以修改它以传递不同的lambda表达式以便检索其他属性。

答案 1 :(得分: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的语法。

答案 2 :(得分: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;
        };

    }

答案 3 :(得分: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);
...