这个静态反射代码有什么用例?

时间:2010-04-07 21:19:44

标签: c# strong-typing static-reflection

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

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)交换机中不同分支的代码示例是什么?什么是这个代码能够强类型?

2 个答案:

答案 0 :(得分:3)

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

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

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

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

这里传递字符串“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时,代码将无法编译,直到您还将表达式更改为读取x => x.PersonName。这是你的类型安全。

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

如果您只是实现INotifyPropertyChanged,那么这并非全是必要的,但也许您也在使用它来验证参数或其他内容;该开关只覆盖任何成员访问表达式的基础,如果你给它任何其他东西,则抛出。

答案 1 :(得分:2)

  • MemberAccessfoo => foo.SomeFieldfoo => foo.SomeProperty
  • Callfoo => foo.SomeMethod(...)
  • Parameterfoo => foo
  • Convertfoo => (int)foo.Something(也许含蓄)