Есть два способа сделать это:
Models.Test test = new Models.Test();
string DisplayName = test.GetDisplayName(t => t.Name);
string DisplayName = Helpers.GetDisplayName<Models.Test>(t => t.Name);
Первый работает на основе написания универсального метода расширения для любой TModel (которая является всеми типами). Это означает, что он будет доступен для любого объекта, а не только для вашей модели. Не очень рекомендуется, но приятно из-за краткого синтаксиса.
Второй метод требует, чтобы вы передали тип модели, которую вы уже используете, - но вместо этого вы используете ее в качестве параметра. Этот метод необходим для определения типа через Generics, потому что Func ожидает его.
Вот методы, которые вы можете проверить.
Метод статического расширения для всех объектов
public static string GetDisplayName<TModel, TProperty>(this TModel model, Expression<Func<TModel, TProperty>> expression) {
Type type = typeof(TModel);
MemberExpression memberExpression = (MemberExpression)expression.Body;
string propertyName = ((memberExpression.Member is PropertyInfo) ? memberExpression.Member.Name : null);
// First look into attributes on a type and it's parents
DisplayAttribute attr;
attr = (DisplayAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayAttribute), true).SingleOrDefault();
// Look for [MetadataType] attribute in type hierarchy
// /931378/attribute-isdefined-ne-vidit-atributy-primenennye-s-klassom-metadatatype
if (attr == null) {
MetadataTypeAttribute metadataType = (MetadataTypeAttribute)type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
if (metadataType != null) {
var property = metadataType.MetadataClassType.GetProperty(propertyName);
if (property != null) {
attr = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
}
}
}
return (attr != null) ? attr.Name : String.Empty;
}
Подпись для конкретного типа метода - тот же код, что и выше, только другой вызов
public static string GetDisplayName<TModel>(Expression<Func<TModel, object>> expression) { }
Причина, по которой вы не можете просто использовать Something.GetDisplayName(t => t.Name)
сама по себе, состоит в том, что в движке Razor вы фактически передаете экземплярный объект HtmlHelper<TModel>
, поэтому первый метод требует создания экземпляра объекта - это требуется только чтобы компилятор мог определить, какие типы принадлежат какому универсальному имени.
Обновление с рекурсивными свойствами
public static string GetDisplayName<TModel>(Expression<Func<TModel, object>> expression) {
Type type = typeof(TModel);
string propertyName = null;
string[] properties = null;
IEnumerable<string> propertyList;
//unless it's a root property the expression NodeType will always be Convert
switch (expression.Body.NodeType) {
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = expression.Body as UnaryExpression;
propertyList = (ue != null ? ue.Operand : null).ToString().Split(".".ToCharArray()).Skip(1); //don't use the root property
break;
default:
propertyList = expression.Body.ToString().Split(".".ToCharArray()).Skip(1);
break;
}
//the propert name is what we're after
propertyName = propertyList.Last();
//list of properties - the last property name
properties = propertyList.Take(propertyList.Count() - 1).ToArray(); //grab all the parent properties
Expression expr = null;
foreach (string property in properties) {
PropertyInfo propertyInfo = type.GetProperty(property);
expr = Expression.Property(expr, type.GetProperty(property));
type = propertyInfo.PropertyType;
}
DisplayAttribute attr;
attr = (DisplayAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayAttribute), true).SingleOrDefault();
// Look for [MetadataType] attribute in type hierarchy
// /931378/attribute-isdefined-ne-vidit-atributy-primenennye-s-klassom-metadatatype
if (attr == null) {
MetadataTypeAttribute metadataType = (MetadataTypeAttribute)type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
if (metadataType != null) {
var property = metadataType.MetadataClassType.GetProperty(propertyName);
if (property != null) {
attr = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
}
}
}
return (attr != null) ? attr.Name : String.Empty;
}