2010-11-24 5 views
2

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

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

Я не уверен, что выход метода 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

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

1
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"); 
    } 
Смежные вопросы