Выражение <Func <TModel, TValue >> как я могу получить имя TValue? - PullRequest
7 голосов
/ 05 января 2011
//ModelFor(person =>person.Name);
public void ModelFor<TModel, TValue>(
    Expression<Func<TModel, TValue>> expression)
{
    //Result should be "Name"
    string nameOfTValue = ????;     
}

Ответы [ 2 ]

9 голосов
/ 05 января 2011

@ Ани: Я не думаю, что это правильно, я думаю, что он хочет имя параметра в выражении типа TValue

Если это правда ... это работает только на 1 уровень, но в любом случае может пригодиться:

var nameOfTValue = ((MemberExpression)expression.Body).Member.Name; 

Вот более разумная реализация, которая должна иметь возможность работать с несколькими уровнями:

 public class PropertyName{
    public static string For<T>(
      Expression<Func<T,object>> expression){
      var body=expression.Body;
      return GetMemberName(body);
    }
    public static string For(
      Expression<Func<object>> expression){
      var body=expression.Body;
      return GetMemberName(body);
    }
    public static string GetMemberName(
      Expression expression){
      if(expression is MemberExpression){
        var memberExpression=(MemberExpression)expression;
        if(memberExpression.Expression.NodeType==
           ExpressionType.MemberAccess)
          return GetMemberName(memberExpression.Expression)
            +"."+memberExpression.Member.Name;
        return memberExpression.Member.Name;
      }
      if(expression is UnaryExpression){
        var unaryExpression=(UnaryExpression)expression;
        if(unaryExpression.NodeType!=ExpressionType.Convert)
          throw new Exception(string.Format
            ("Cannot interpret member from {0}",expression));
        return GetMemberName(unaryExpression.Operand);
      }
      throw new Exception
        (string.Format("Could not determine member from {0}",expression));
    }
  }

Использование:

var fieldName=PropertyName.For<Customer>(x=>x.Address.Region);
//fieldName==Address.Region

Еще один трюк, который можно красиво сочетать с отражением:

public static T Set<T,TProp>(this T o,
   Expression<Func<T,TProp>> field,TProp value){
  var fn=((MemberExpression)field.Body).Member.Name;
  o.GetType().GetProperty(fn).SetValue(o,value,null);
  return o;
}

Позволяет легко устанавливать свойства, может быть полезен для тестовых приборов:

var customer=new Customer("firstName","lastName");
customer.Set(x=>x.Name, "different firstName");
8 голосов
/ 05 января 2011

РЕДАКТИРОВАТЬ : После вашего редактирования, я думаю, вам нужно имя члена, участвующего в выражении, при условии, конечно, что выражение является выражением-членом в первую очередь.

((MemberExpression)expression.Body).Member.Name

Чтобы быть более устойчивым, вы можете сделать:

var memberEx = expression.Body as MemberExpression;

if (memberEx == null)
     throw new ArgumentException("Body not a member-expression.");

string name = memberEx.Member.Name;

(больше не актуально):

Чтобы получить System.Type, представляющий тип аргумента типа TValue, вы можете использовать оператор typeof.

Вы, вероятно, хотите:

typeof(TValue).Name

Но при необходимости также учитывайте свойства FullName и AssemblyQualifiedName.

Это действительно не имеет ничего общего с деревьями выражений; Вы можете использовать эту технику, чтобы получить тип аргумента типа для любого универсального метода.

...