我们可以修改此代码以返回方法的名称而不是属性吗?

时间:2011-03-25 22:17:52

标签: c#

寻找一种干净的方法来以类型安全的方式发现方法的字符串名称。

以下是我对属性的看法,但我无法弄清楚如何为方法做到这一点。

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

3 个答案:

答案 0 :(得分:5)

几乎改为:

    var expression = (MethodCallExpression)selector.Body;
    return expression.Method.Name;

除了明显的例外,您需要Action<T>选项来处理void方法。当然,你必须提供虚拟参数值 - 如果真的想要你也可以获得它们。

实际上,您的现有代码可能不健全;你可能需要抛弃一个强制转换操作(将int装入一个对象)。

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

答案 1 :(得分:1)

如果有帮助,我们的代码库使用以下内容:

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

这使你有能力:

var propertyName = TypeHelper.GetPropertyName<Customer>(c => c.Id);

或者

var propertyName = TypeHelper.GetPropertyName(() => this.Id); // If inside Customer class

答案 2 :(得分:0)

如果您恰好拥有System.Web.Mvc,可以使用ExpressionHelper.GetExpressionText(expression),如下所示:

Expression<Func<Response, string>> expression = r => r.Message;
Assert.AreEqual("Message", ExpressionHelper.GetExpressionText(expression));

Response是一个带有Message属性的自定义类。)