为什么这个Lambda表达式被转换为MemberExpression和UnaryExpression?

时间:2016-03-26 13:31:27

标签: c# lambda

我是c#和lambda表达式的新手;在this教程中,我无法理解代码对此Lambda表达式的作用:

public ViewModel()
{
    base.AddRule(() => Aid, () =>
    Aid.Length >= (5 * 2) &&
    Aid.Length <= (16 * 2) &&
    Aid.Length % 2 == 0, "Invalid AID.");
}

这是AddRule方法,教程说它将规则添加到规则字典中:

public void AddRule<T>(Expression<Func<T>> expression, Func<bool> ruleDelegate, string errorMessage)
{
    var name = GetPropertyName(expression);

    ruleMap.Add(name, new Binder(ruleDelegate, errorMessage));
}

protected static string GetPropertyName<T>(Expression<Func<T>> expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            Expression body = expression.Body;
            MemberExpression memberExpression = body as MemberExpression;
            if (memberExpression == null)
            {
                memberExpression = (MemberExpression)((UnaryExpression)body).Operand;
            }
            return memberExpression.Member.Name;
        }

    }

() => Aid是什么意思以及为什么addrule收到它并将其转换为UnaryExpression和MemberExpression?

3 个答案:

答案 0 :(得分:2)

() => Aid() => { return Aid; }的简写,它返回一个属性(或字段 - 您没有显示其声明)。通常这会导致匿名函数。

但是因为AddRule方法采用Expression<Func<T>>而不是Func<T>,编译器会创建指令来创建AST(抽象语法树)而不是匿名函数。 AST可以编译成方法,但这里它只用于提取属性/字段的名称。

另一种方法是将属性名称作为字符串传递。使用成员表达式的优点在于它的重构友好:重命名属性也将更新此代码,确保规则仍与正确的属性相关联。

这是实际传递给AddRule的内容(您可以手动执行此操作,但是您将失去对重构友好的好处 - 此外,() => Aid更简洁):

Expression.Lambda<Func<T>>(
    Expression.Property(
        Expression.Constant(this),
        "Aid"));

答案 1 :(得分:2)

MemberExpression是实例上的表达式或MemberInfo的静态表达式。

UnaryExpression是一个围绕目标和单个运算符的表达式(请参阅术语一元的定义)。这种运算符的一个很好的例子是演员。另一个是对值类型进行装箱或取消装箱的操作。

那么为什么获取MemberInfo的示例需要处理UnaryExpression?

考虑

public class Foo
{
    public String RefType { get; set; }
    public int ValueType { get; set; }
}

和一些代码

Expression<Func<Foo, object>> getter;
getter = f => f.RefType // compiler emits MemberExpression for RefType on a Foo instance
getter = f => f.ValueType // compiler emits an UnaryExpression to Box a MemberExpression for ValueType on a Foo instance.

答案 2 :(得分:1)

Aid是该示例中使用的viewmodel的属性:

    public string Aid
    {
        get { return Get(() => Aid); }
        set { Set(() => Aid, value); }
    }

如果您从该文章下载整个项目(链接在顶部)

,您可以检查这一点

将属性传递给lambda表达式时,它将由MemberExpression表示。如MemberExpression Class

中所述,此课程专门用于此课程