3

这是Oliver Hanappi在 stackoverflow 上发布的静态反射代码

private static string GetMemberName(Expression expression)
    {
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                var memberExpression = (MemberExpression)expression;
                var supername = GetMemberName(memberExpression.Expression);

                if (String.IsNullOrEmpty(supername))
                    return memberExpression.Member.Name;

                return String.Concat(supername, '.', memberExpression.Member.Name);

            case ExpressionType.Call:
                var callExpression = (MethodCallExpression)expression;
                return callExpression.Method.Name;

            case ExpressionType.Convert:
                var unaryExpression = (UnaryExpression)expression;
                return GetMemberName(unaryExpression.Operand);

            case ExpressionType.Parameter:
                return String.Empty;

            default:
                throw new ArgumentException("The expression is not a member access or method call expression");
        }
    }

我有公共包装方法:

public static string Name<T>(Expression<Action<T>> expression)
    {
        return GetMemberName(expression.Body);
    }
public static string Name<T>(Expression<Func<T, object>> expression)
    {
        return GetMemberName(expression.Body);
    }

然后添加了我自己的方法快捷方式

        public static string ClassMemberName<T>(this T sourceType,Expression<Func<T,object>> expression)
    {
        return GetMemberName(expression.Body);
    }
    public static string TMemberName<T>(this IEnumerable<T> sourceList, Expression<Func<T,object>> expression)
    {
        return GetMemberName(expression.Body);
    }

哪些代码示例需要或利用GetMemberName(Expression expression)交换机中的不同分支?这段代码能够进行强类型化的全部内容是什么?

4

2 回答 2

3

许多需要您传递幻数(包含人们有时称为“幻数”的通用术语)的东西可以使用表达式来提供类型安全。

一个常见的例子是INotifyPropertyChanged接口的实现。

通常,您的属性设置器包括如下调用:

string _name
public string name
{
    get { return _name; }
    set
    {
        if(value.Equals(_name)) return;
        _name = value;
        OnPropertyChanged("name");
    }
}

在这里,您传递字符串“名称”以标识已更改的属性。当您的团队负责人说“让所有公共属性以大写字母开头......并在它们前面加上类名”时,这会变得很糟糕。现在您将属性更改为PersonName,但您记得更改为的可能性有"name"多大"PersonName"?不高,尤其是如果您最初没有编写代码。尽管如此,该项目仍将编译,您将花费 20 分钟进行调试。

相反,您使用表达式:

string _name
public string name
{
    get { return _name; }
    set
    {
        if(value.Equals(_name)) return;
        _name = value;
        OnPropertyChanged(x => x.name);
    }
}

...并且您的OnPropertyChanged实现使用您发布的代码从表达式主体中获取属性的名称。

现在,当您将属性更改为 时PersonName,代码不会编译,直到您也将表达式更改为 read x => x.PersonName。这是您的类型安全。

代码显然使用了开关,因为表达式可能包含任何类型的节点;它不一定是MemberExpression访问属性——它可以引用方法调用、方法的参数等。

如果您只是实现INotifyPropertyChanged,这并不是所有必要的,但也许您还使用它来验证参数或其他东西;开关只覆盖任何成员访问表达式的基础,如果你给它其他任何东西,就会抛出。

于 2010-04-07T21:52:54.187 回答
2
  • MemberAccessfoo => foo.SomeFieldfoo => foo.SomeProperty
  • Callfoo => foo.SomeMethod(...)
  • Parameterfoo => foo
  • Convert: foo => (int)foo.Something(也许是隐含的)
于 2010-04-07T21:37:12.017 回答