Каковы варианты использования для этого статического кода отражения?

Это код статического отражения Oliver Hanappi он выложил в stackru

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 ответа

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

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

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

Другие вопросы по тегам