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

#c# #asp.net-mvc #lambda #reflection

Вопрос:

У меня есть следующее определение класса

Персона.cs

 class Person {

  [Column("first_name")]
  public string FirstName { get; set; }

  [Column("last_name")]
  public string LastName { get; set; }
}
 

Я написал вспомогательное расширение HTML для извлечения ColumnAttribute значения из данного экземпляра. Однако это работает не так, как я ожидаю.

Вот что я попробовал:

Индекс.cshtml

 @model Person
<p>ColumnName is @Html.ColumnNameFor( model => model.FirstName )</p>
 

HtmlExtensions.cs (общедоступный статический класс)

 public static string ColumnNameFor<T, P>(this HtmlHelper<T> helper, Expression<Func<T, P>> expression)
{
    var name = ExpressionHelper.GetExpressionText(expression);
    var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);

    // this line causes a runtime error:
    //  Sequence contains no elements
    var attr = (ColumnAttribute)metadata.GetType().GetCustomAttributes(typeof(ColumnAttribute), false).First();
            
  return attr.Name;    // ColumnAttribute stores the value in .Name
}
 

Для справки, я могу извлечь значение с помощью GetCustomAttributes , при условии, что я передаю ссылку на свойство, которое, я думаю, заставит код в представлении сильно отличаться от встроенного кода ASP MVC для Html.TextBoxFor и Html.DisplayFor и т. Д.

Ответ №1:

Благодаря @benuto за его ответ, я смог выяснить, как я мог извлечь любой требуемый пользовательский атрибут или свойство с помощью MemeberExpress . Я хотел, чтобы ответ помог другим, поэтому я привел рабочий пример. Имейте в виду, что вам нужно будет проверить, имеет ли объект пользовательское свойство или нет, чтобы избежать сбоя при доступе FirstOrDefault().Name .

  public static string ColumnNameFor<T, P>( this HtmlHelper<T> helper, 
                                           Expression<Func<T, P>> expression)
 {
      var name = ExpressionHelper.GetExpressionText(expression);

      MemberExpression me = expression.Body as MemberExpression;

      var cp = (ColumnAttribute)me
                  .Member
                  .GetCustomAttributes(typeof(ColumnAttribute), false)
                  .FirstOrDefault();

      return (cp == null) ? null : cp.Name;
 }