Каковы варианты использования для этого статического кода отражения? - PullRequest
3 голосов
/ 08 апреля 2010

Это Код статического отражения Оливера Ханаппи , который он отправил в стеке

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 ]

3 голосов
/ 08 апреля 2010

Многие вещи, которые требуют, чтобы вы передавали магические числа (общий термин, охватывающий то, что люди иногда называют «магическими строками»), могут вместо этого использовать выражения для обеспечения безопасности типов.

Типичным примером является реализация интерфейса 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, но, возможно, вы также используете его для проверки параметров или чего-то еще; переключатель просто охватывает основы для любого выражения доступа к элементу и выдает его, если вы дадите ему что-нибудь еще.

2 голосов
/ 08 апреля 2010
  • MemberAccess: foo => foo.SomeField или foo => foo.SomeProperty
  • Call: foo => foo.SomeMethod(...)
  • Parameter: foo => foo
  • Convert: foo => (int)foo.Something (возможно, неявно)
...