2

我有以下扩展方法:

public static string ToPropertyName<T,E>(this Expression<Func<E, T>> propertyExpression)
{
    if (propertyExpression == null)
        return null;

    string propName;
    MemberExpression propRef = (propertyExpression.Body as MemberExpression);
    UnaryExpression propVal = null;

    // -- handle ref types
    if (propRef != null)
        propName = propRef.Member.Name;
    else
    {
        // -- handle value types
        propVal = propertyExpression.Body as UnaryExpression;
        if (propVal == null)
            throw new ArgumentException("The property parameter does not point to a property", "property");
        propName = ((MemberExpression)propVal.Operand).Member.Name;
    }

    return propName;
}

我在传递属性名称而不是字符串时使用 linq 表达式来提供强类型,我使用此函数将属性名称作为字符串检索。这种方法是否使用反射?

我问的原因是这种方法在我们的代码中被大量使用,我希望它足够快。

4

2 回答 2

2

As far as I know, reflection is not involved in the sense that some kind of dynamic type introspection happens behind the scenes. However, types from the System.Reflection such as Type or PropertyInfo are used together with types from the System.Linq.Expressions namespace. They are used by the compiler only to describe any Func<T,E> passed to your method as an abstract syntax tree (AST). Since this transformation from a Func<T,E> to an expression tree is done by the compiler, and not at run-time, only the lambda's static aspects are described.

Remember though that building this expression tree (complex object graph) from a lambda at run-time might take somewhat longer than simply passing a property name string (single object), simply because more objects need to be instantiated (the number depends on the complexity of the lambda passed to your method), but again, no dynamic type inspection à la someObject.GetType() is involved.

Example:

This MSDN article shows that the following lambda expression:

Expression<Func<int, bool>> lambda1 = num => num < 5;

is transformed to something like this by the compiler:

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

Beyond this, nothing else happens. So this is the object graph that might then be passed into your method.

于 2012-07-06T08:50:48.107 回答
0

由于您的方法命名是ToPropertyName,我想您正在尝试获取类的某些特定属性的类型名称。您是否对方法进行了基准测试Expression<Func<E, T>>?创建表达式的成本相当大,而且由于您的方法是静态的,我看到您也没有缓存成员表达式。换句话说,即使表达式方法不使用反射,成本也会很高。请参阅此问题:如何将 C# 属性名称作为带有反射的字符串?你有另一种方法:

public static string GetName<T>(this T item) where T : class
{
    if (item == null)
        return string.Empty;

    return typeof(T).GetProperties()[0].Name;
}

您可以使用它来获取属性或变量的名称,如下所示:

new { property }.GetName();

为了进一步加快速度,您需要缓存成员信息。如果你所拥有的绝对是Func<E, T>那么你的方法适合。另请参阅:基于 lambda 表达式的反射与正常反射

一个相关问题:将所有属性名称和对应的值放入字典中

于 2013-04-17T10:32:53.733 回答