【问题标题】:Is reflection used when retrieving information from a linq expression?从 linq 表达式中检索信息时是否使用反射?
【发布时间】:2012-07-06 08:30:45
【问题描述】:

我有以下扩展方法:

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 表达式来提供强类型,我使用此函数将属性名称作为字符串检索。这个方法使用反射吗?

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

【问题讨论】:

标签: c# expression-trees linq-expressions


【解决方案1】:

据我所知,反射并不涉及某种动态类型自省发生在幕后的意义上。但是,System.Reflection 中的类型(例如 TypePropertyInfo)与 System.Linq.Expressions 命名空间中的类型一起使用。编译器仅使用它们来描述作为抽象语法树 (AST) 传递给您的方法的任何 Func&lt;T,E&gt;。由于从Func&lt;T,E&gt; 到表达式树的转换是由编译器完成的,而不是在运行时完成的,因此只描述了 lambda 的静态方面。

请记住,尽管在运行时从 lambda 构建此表达式树(复杂对象图)可能比简单地传递属性名称字符串(单个对象)要长一些,因为需要实例化更多对象(数量取决于关于传递给您的方法的 lambda 的复杂性),但同样,不涉及动态类型检查 à la someObject.GetType()

示例:

This MSDN article 显示以下 lambda 表达式:

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

被编译器转换成这样的东西:

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

除此之外,没有其他事情发生。所以这是可以传递给你的方法的对象图。

【讨论】:

    【解决方案2】:

    由于您的方法命名是ToPropertyName,我想您正在尝试获取某个类的某些特定属性的类型名称。您是否对Expression&lt;Func&lt;E, T&gt;&gt; 方法进行了基准测试?创建表达式的成本相当大,而且由于您的方法是静态的,我看到您也没有缓存成员表达式。换句话说,即使表达式方法不使用反射,成本也会很高。看到这个问题:How do you get a C# property name as a string with reflection? 你有另一种方法:

    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&lt;E, T&gt;,那么您的方法就很合适。另请参阅:lambda expression based reflection vs normal reflection

    一个相关问题:Get all the property names and corresponding values into a dictionary

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多