#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;
}