Строго типизированные объявления свойств - этот код безопасен? - PullRequest
2 голосов
/ 24 ноября 2010

Мне интересно, является ли следующий код "безопасным". Под «безопасным» я подразумеваю, что я не зависим от какой-либо конкретной версии компилятора или недокументированной функции. Я хочу получить строку с именем свойства / поля, но я хочу объявить ее, используя строгую типизацию (я хочу, чтобы компилятор проверил, существует ли конкретное поле / свойство). Мой метод выглядит так:

string GetPropertyName<T>(Expression<Func<T, object>> expression)
{
    if (expression.Body is UnaryExpression)
    {
        var operand = ((UnaryExpression)expression.Body).Operand.ToString();
        return operand.Substring(operand.IndexOf(".") + 1);
    }
    else if (expression.Body is MemberExpression)
    {
        return ((MemberExpression)expression.Body).Member.Name;
    }
    else
    {
        throw new NotImplementedException();
    }            
}

А вот как я хочу это использовать:

class Foo
{
    public string A { get; set; }
    public Bar B { get; set; }
}

class Bar
{
    public int C { get; set; }
    public Baz D { get; set; }
}

class Baz
{
    public int E { get; set; }
}


GetPropertyName<Foo>(x => x.A)
GetPropertyName<Foo>(x => x.B)
GetPropertyName<Foo>(x => x.B.C)
GetPropertyName<Foo>(foo => foo.B.D.E)

Заранее спасибо за помощь.

Ответы [ 3 ]

3 голосов
/ 24 ноября 2010

Я не уверен, что выход метода ToString гарантирован в любом случае. В документации просто сказано, что она "возвращает текстовое представление Expression" .

(Я подозреваю, что выходные данные вряд ли изменятся на разных платформах / версиях, но я бы неохотно полагался на них, когда ваша цель - использовать строгую типизацию, проверки во время компиляции и т.

Вот мой метод, который делает нечто подобное без использования ToString:

public static string GetPropertyName<T>(Expression<Func<T, object>> e)
{
    MemberExpression me;
    switch (e.Body.NodeType)
    {
        case ExpressionType.Convert:
        case ExpressionType.ConvertChecked:
            var ue = e.Body as UnaryExpression;
            me = ((ue != null) ? ue.Operand : null) as MemberExpression;
            break;
        default:
            me = e.Body as MemberExpression;
            break;
    }

    if (me == null)
        throw new ArgumentException("Expression must represent field or property access.", "e");

    var stack = new Stack<string>();

    do
    {
        stack.Push(me.Member.Name);
        me = me.Expression as MemberExpression;
    } while (me != null);

    return string.Join(".", stack);    // use "stack.ToArray()" on .NET 3.5
}
2 голосов
/ 24 ноября 2010

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

1 голос
/ 21 июля 2011
    public static string GetPropertyName<T>(Expression<Func<T, object>> e)
    {
        if (e.Body is MemberExpression)
            return ((MemberExpression)e.Body).Member.Name;
        else if (e.Body is UnaryExpression)
            return ((MemberExpression)((UnaryExpression)e.Body).Operand).Member.Name;

        throw new ArgumentException("Expression must represent field or property access.", "e");
    }
...