为何使用表达式树

时间:2015-09-28 07:31:54

标签: .net expression-trees

我不知道为什么我在阅读表情树,但我是。因此,我不了解对象,或者它在何处或如何使用。

在这里阅读其他问题,例如What are Expression Trees and how do you use them and why would you use them?(以及他们引用的链接),我现在更了解表达树了但是,我仍然对为什么它被使用。

我见过的唯一一个例子就是Linq to SQL - 但是当你对它进行更多的研究时,它实际上更多地是关于它与{{1}的一起使用} interface。

表达式树是否仅与IQueryable<T>接口一起使用(使用)?

3 个答案:

答案 0 :(得分:4)

这有点像是同义反复,但答案是&#34;每当你需要理解表达时,#34;

我从初级开发人员那里看到的一个常见问题是&#34; Func<T>Expression<Func<T>>之间有什么区别?&#34;对于大多数人来说,后者要求你在表达式上调用Compile()来获得它所代表的函数,否则他们看起来会做同样的工作。

表达式树让编译器将通常作为指令的指令嵌入到可探索的表达式树中。如果您正在编写的东西不仅需要理解函数的结果,而且还需要了解调用者如何构造函数,表达式树可以为您捕获。

在差异变得相关之前,您需要知道表达式的组合方式

我只看到两种方式使用的表达方式:

  1. 创建LINQ提供程序(如LINQ-to-SQL)来解释表达式并将其转换为另一种语言。如您所知,这涉及实施IQueryable并且是一项大交易。
  2. 从对象(如Razor HTML Helpers)捕获属性访问器,因此不仅可以访问该值,还可以使用该属性的名称来生成内容(如HTML字段名称)。
  3. 常见的任务往往是对另一种语言的某种翻译。对于LINQ提供程序,它是将查询直接转换为另一种查询语言。在Razor的情况下,它将属性转换为HTML字段。

答案 1 :(得分:2)

当您需要解析此表达式时经常使用它,例如确定表达式参数名称或类似的东西。例如,在.NET中有ArgumentNullException,要创建一个这样的实例,你应该将参数名称作为字符串传递,它不是类型安全的方法,所以你可以使用这个包装器:

    public static string GetName<T>(this Expression<Func<T>> expr)
    {
        if (expr.Body.NodeType == ExpressionType.MemberAccess)
            return ((MemberExpression)expr.Body).Member.Name;

        if (expr.Body.NodeType == ExpressionType.Convert
            && ((UnaryExpression)expr.Body).Operand.NodeType
            == ExpressionType.MemberAccess)
            return ((MemberExpression)((UnaryExpression)expr.Body).Operand)
                .Member.Name;

        throw new ArgumentException(
            "Argument 'expr' must be of the form ()=>variableName.");
    }

    public static void CheckForNullArg<T>(params Expression<Func<T>>[] expressions)
    {
        foreach (var expression in expressions)
        {
            if (EqualityComparer<T>.Default.Equals(expression.Compile()(), default(T)))
            {
                throw new ArgumentNullException(expression.GetName());
            }
        }
    }

    public void Test(string parameter)
    {
        CheckForNullArg(() => parameter);
    }

另一个类似的用法是WPF中的类型安全处理PropertyChanged事件 - Handling PropertyChanged in a type-safe way

除此之外,它对于日志记录很有用,因为您可以将Expression的字符串表示保存在日志中,调用ToString()。

答案 2 :(得分:2)

表达式树通常用于在运行时动态生成代码。 让我们说你必须创建许多未知类型的insatnces。 您可以使用反射创建它们,并且您将遭受性能不佳,或者您可以创建表达式树并将其编译为方法。 该方法的性能与编译时的性能相同 使用visual studio。

public static class TypeFactory
{
    private static Dictionary<Type, object> dictionary = new Dictionary<Type, object>();

    public static Func<TType> CreateFactory<TType>() {
        object factory;
        var typeofType = typeof(TType);

        if (dictionary.TryGetValue(typeofType, out factory)) {
            return (Func<TType>)factory;
        }

        return CreateCachedFactory<TType>(typeofType);
    }

    private static Func<TType> CreateCachedFactory<TType>(Type typeofType) {
        var ctorInfo = typeofType.GetConstructor(Type.EmptyTypes);
        var lambdaExpression = Expression.Lambda<Func<TType>>(Expression.New(ctorInfo));
        var factory = lambdaExpression.Compile();

        dictionary.Add(typeofType, factory);

        return factory;
    }
}

public class MyClass
{
}

static class Program
{

    static void Main() {
        var myClassFactory = TypeFactory.CreateFactory<MyClass>();
        var instance = myClassFactory();

        Console.WriteLine(instance.GetType().FullName);
    }
}

幕后花絮表树正在使用lcg或light code生成 使用Reflection.Emit构造方法,这很难理解,所以你可能会说表达式树也是代码生成的抽象。