2010-04-07 2 views
3

Это Oliver Hanappi «S статический код отражения ситемы posted на 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) переключатель? что все этот код способен сделать строго типизированным?

+1

Этот вопрос кажется мне немного странным. Если вы не знали, для чего собираетесь использовать этот код, почему вы его расширили? –

+0

Я знаю, для чего его используют. Я спрашиваю о неочевидном использовании. Я использовал его широко, но я до сих пор не знаю, на что все это способно или что то, что я сделал, использует больше, чем одна его ветвь. – Maslow

ответ

2
  • MemberAccess: foo => foo.SomeField или foo => foo.SomeProperty
  • Call: foo => foo.SomeMethod(...)
  • Parameter: foo => foo
  • Convert: foo => (int)foo.Something (возможно, неявные)
+0

спасибо, это именно то, что я хотел знать. Я предполагаю, что это исчерпывающий список? Я даже не думал об использовании этого для имени параметра, я предполагаю, что работает только для параметров локальной переменной и нет способа получить имя имени параметра другого метода? – Maslow

+0

@Maslow; если вы посмотрите, он даже не возвращает имя параметра (он возвращает «»). Вы * можете * получить «foo» из «ParameterExpression», или вы можете получить имя параметра method'd, сопоставив его с 'MethodInfo' и используя' GetParameters() '. –

+0

'MethodInfo' +' GetParameters() 'будет фактическим отражением с поражением производительности, а не статическим отражением с небольшими/отсутствующими проблемами производительности? – Maslow

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, код не скомпилируется, пока вы также не смените выражение на x => x.PersonName. Это ваш тип безопасности.

Код, очевидно, использует переключатель, поскольку выражение может содержать узлы любого типа; не обязательно MemberExpression для доступа к объекту - он может ссылаться на вызов метода, параметр метода и т. д.

Это не обязательно, если вы только реализуете INotifyPropertyChanged, но, возможно, вы также являетесь используя его для проверки параметров или чего-то еще; коммутатор просто охватывает базы для любого выражения доступа к члену и бросает, если вы дадите ему что-нибудь еще.