Can we modify this code to return the name of a method instead of a property?
Looking fo开发者_开发百科r a clean way to discover the string name of a method in a type safe way.
Here is what I have for properties, but I'm having trouble figuring out how to do it for methods.
class Program
{
class Customer
{
public String Id { get; set; }
}
public static String GetPropertyName<T>(
Expression<Func<T, Object>> selector) where T : class
{
var expression = (MemberExpression)selector.Body;
return expression.Member.Name;
}
static void Main(string[] args)
{
String propertyName = GetPropertyName<Customer>(c => c.Id);
}
}
Pretty much by changing to:
var expression = (MethodCallExpression)selector.Body;
return expression.Method.Name;
with the notable exception that you will need an Action<T>
option to handle void
methods. You will have to supply dummy parameter values, of course - if you really want you can obtain those too.
Actually, your existing code might not be robust; you may need to throw away a cast operation (to box the int to an object).
public static string GetMethodName<T>(Expression<Func<T, Object>> selector) where T : class
{
var expression = (MethodCallExpression)(selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body);
return expression.Method.Name;
}
public static string GetMethodName<T>(Expression<Action<T>> selector) where T : class
{
var expression = (MethodCallExpression)(selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body);
return expression.Method.Name;
}
If it helps, our code base uses the following:
public class TypeHelper
{
private static PropertyInfo GetPropertyInternal(LambdaExpression p)
{
MemberExpression memberExpression;
if (p.Body is UnaryExpression)
{
UnaryExpression ue = (UnaryExpression)p.Body;
memberExpression = (MemberExpression)ue.Operand;
}
else
{
memberExpression = (MemberExpression)p.Body;
}
return (PropertyInfo)(memberExpression).Member;
}
public static string GetPropertyName<TObject>(Expression<Func<TObject, object>> p)
{
return GetPropertyNameInternal(p);
}
public static string GetPropertyName<TObject, T>(Expression<Func<TObject, T>> p)
{
return GetPropertyNameInternal(p);
}
public static string GetPropertyName<T>(Expression<Func<T>> p)
{
return GetPropertyNameInternal(p);
}
public static string GetPropertyName(Expression p)
{
return GetPropertyNameInternal((LambdaExpression) p);
}
private static string GetPropertyNameInternal(LambdaExpression p)
{
return GetPropertyInternal(p).Name;
}
public static PropertyInfo GetProperty<TObject>(Expression<Func<TObject, object>> p)
{
return GetPropertyInternal(p);
}
public static PropertyInfo GetProperty<TObject, T>(Expression<Func<TObject, T>> p)
{
return GetPropertyInternal(p);
}
public static PropertyInfo GetProperty<T>(Expression<Func<T>> p)
{
return GetPropertyInternal(p);
}
}
That gives you the ability to do:
var propertyName = TypeHelper.GetPropertyName<Customer>(c => c.Id);
Or
var propertyName = TypeHelper.GetPropertyName(() => this.Id); // If inside Customer class
If you happen to have System.Web.Mvc
, you can use ExpressionHelper.GetExpressionText(expression)
, like so:
Expression<Func<Response, string>> expression = r => r.Message;
Assert.AreEqual("Message", ExpressionHelper.GetExpressionText(expression));
(Response
being a custom class with a Message property.)
精彩评论