【问题标题】:What are the use cases for this static reflection code?这个静态反射代码的用例是什么?
【发布时间】:2011-02-05 11:09:00
【问题描述】:

这是Oliver Hanappiposted在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) 开关中的不同分支?这段代码到底能做什么强类型?

【问题讨论】:

  • 这个问题对我来说似乎有点奇怪。如果您不知道要使用代码做什么,为什么要扩展它?
  • 我知道它的哪些部分是用来做的。我问的是非显而易见的用途。我已经广泛使用了它,但我仍然不知道它的全部功能,或者我所做的是否只使用了它的一个分支。

标签: c# strong-typing static-reflection


【解决方案1】:
  • MemberAccess : foo =&gt; foo.SomeFieldfoo =&gt; foo.SomeProperty
  • Callfoo =&gt; foo.SomeMethod(...)
  • Parameterfoo =&gt; foo
  • Convert : foo =&gt; (int)foo.Something(可能是隐含的)

【讨论】:

  • 谢谢,这正是我想知道的。我认为这是一个详尽的清单?我从来没想过用这个作为参数名,我假设它只适用于局部变量参数并且没有办法获取另一个方法的参数名?
  • @马斯洛;如果你看,它甚至不返回参数名称(它返回“”)。您可以ParameterExpression 获取“foo”,或者您可以通过将其映射到MethodInfo 并使用GetParameters() 来获取方法的参数名称。
  • MethodInfo + GetParameters() 将是性能受到影响的实际反射,而不是几乎没有/没有性能问题的静态反射,对吧?
  • all 这一切都是实际的反射...Expression 仍然是围绕反射 API 构建的。唯一的小调整是 C# 编译器可以直接引用 MethodInfo 而不是使用 GetMethod()
  • 嗯,我的印象是它没有一些反射概念所具有的性能影响?
【解决方案2】:

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

一个常见的例子是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 时,代码不会编译,除非您也将表达式更改为 x =&gt; x.PersonName。这是您的类型安全。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2013-08-18
    • 2011-09-11
    • 2019-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多