c# - expression.bind 和 expression.assign 之间有什么区别(或 : what is special about MemberBinding)

标签 c# expression-trees

所以,这是进入细节和 bolt ,但我希望这里有人可以有见识。

这是我设法收集到的内容(当然,我可能有任何错误,所以请纠正我)

Expression.Bind

Based on my research, including the MSDN Entry on the [topic][1], it seems that the Expression.Bind method is used to generate an expression of type MemberAssignment, which is a specific subtype of MemberBinding expressions. The method takes MemberInfo and the expression to which it should be bound. The resulting MemberAssignment expression represents the initialization of a member.

表达式.赋值

Is a method that creates a BinaryExpression that represents an assignment operation

这是我的问题:为什么我们不能在为 Expression.MemberInit 方法提供绑定(bind)时只使用 Expression.Assign?而不是:

    MemberAssignment binding = Expression.Bind(PropAccessMethodInfo, TargetExpression)

例如,我们可以执行以下操作:

    MemberExpression getProperty = Expression.Property(FindObjectExpression, PropAccessMethodInfo)
    Expression binding = Expression.Assign(getProperty, TargetExpression)

我知道编译器会报错,但我想我想问的是这里是否存在不仅仅是句法问题。 换句话说,Expression.Bind/MemberBindings 是否在幕后为我们提供了一些额外的东西?或者,它们只是语法糖,可以更轻松地管理成员初始化?

更具体地说,它是否可以帮助跟踪业务对象与 .NET EF4 中的底层实体之间的关系?它是否以某种方式适合 Entity Framework 中的“使用代理”或帮助更改跟踪或业务对象与基于 EF 的数据访问层之间的桥梁?

正如您可能预见到的那样,我正在尝试以编程方式连接来自底层组件实体的业务对象的创建,并且此类表达式(尤其是 MemberInit 方法)肯定有助于创建位。

但是,我不确定 EF/.NET 是否足够智能以使用这些绑定(bind)进行跟踪?或者,我是否可以将那些相同的绑定(bind)重用到 Biz<->Ent 跟踪/桥。

我希望这是有道理的。如果有什么不清楚的地方,我很乐意提供更多信息。

谢谢!!

最佳答案

对象初始化器是一个复杂的语法糖...它只是语法糖,因为在 IL 级别没有任何类似于对象初始化器的东西...没有特殊指令...只有 C# 编译器编写指令以某种顺序,但可以在不使用 OI 的情况下编写相同的代码。遗憾的是,很少有人描述这种糖的确切工作原理。

现在我将向您展示为什么它是复杂语法糖!

你可以这样认为:

foo = new Foo { Bar = 5 };

翻译成

foo = new Foo();
foo.Bar = 5;

但事实上你知道它不是......假设 foo 是一个属性......当然它不会被访问两次(一次写入用于保存 new Foo() 和一次访问 foo.Bar)...

所以代码可以/应该等于:

Foo tmp = new Foo();
foo = tmp;
tmp.Bar = 5;

但事实并非如此!它可能更类似于

Foo tmp = new Foo();
tmp.Bar = 5;
foo = tmp;

区别在于如果Foo.Bar的setter抛出异常,foo不会被设置!

您可以在以下网址试用:http://ideone.com/PjD7zF

源代码:

using System;

class Program
{
    class Foo
    {
        public Foo()
        {
            Console.WriteLine("Building Foo");
        }

        public int Bar
        {
            get
            {
                Console.WriteLine("Getting Foo.Bar");
                return 0;
            }

            set
            {
                Console.WriteLine("Setting Foo.Bar: boom!");
                throw new Exception();
            }
        }
    }

    static Foo foo2;

    static Foo foo
    {
        get
        {
            Console.WriteLine("Getting foo");
            return foo2;
        }

        set
        {
            Console.WriteLine("Setting foo");
            foo2 = value;
        }
    }

    static void Main(string[] args)
    {
        try
        {
            foo = new Foo { Bar = 100 };

            // Not executed, only to disassemble and check 
            // that it isn't using special instructions!
            foo = new Foo();
            foo.Bar = 200;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: {0}", ex);
        }

        Console.WriteLine("Finished try/catch");

        Console.WriteLine("foo initialized: {0}", foo != null);
    }
}

这种不那么微妙的差异,加上语法糖的复杂性,肯定足以创建一个“特殊的”Expression,它只为此构建(表达式.MemberInit).

Expression.Bind 是必需的,因为他们想准确模拟对象初始化器的工作,而在对象初始化器中你无权访问新的“this”目的。你不能写:

// wrong
foo = new Foo { this.Bar = 5 };

而且他们不希望你能够写出像这样的表达式

foo = new Foo { somethingElse.Prop = 10 } 

如果 Expression.MemberInit 简单地接受一个 Expression.Assign 数组,那将是可能的。

第二点... Expression.MemberInit 在 .NET 3.5 中(这是必要的,因为成员初始化在 LINQ 中很常用),Expression.Assign 只是在 .NET 4.0 中。表达式树是为 LINQ 诞生和构建的(至少 LINQ 减去了 LINQ to Objects,因为 LINQ to Objects 不使用表达式树)。 Expression.Assign 不是必需的,因此未实现。 Expression.MemberInit 是必要的,所以实现了。

第三点...成员初始化在 LINQ 中很常见,因此必须从成员初始化的“基本”部分(临时变量、一些赋值...)构建所有表达式肯定更困难(并且这些表达式在调试时肯定更复杂)而不是使用“一体式”预构建方法。

第四点... LINQ 提供程序通常不会实现所有可能的 Expression(s),并且经常必须处理这样一个事实,即表达式将在远程完全执行不同的环境(参见例如在 SQL Server 上执行 LINQ 查询的 LINQ-to-SQL)。 Expression.MemberInitExpression.Assign 限制更多,因此更容易由 LINQ 提供程序实现。

所以选择这些原因中的一些...它们都很好,可能其中任何一个单独都足以决定实现一个Expression.MemberInit .四个在一起?

关于c# - expression.bind 和 expression.assign 之间有什么区别(或 : what is special about MemberBinding),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18052448/

相关文章:

c# - 用 <T> 实现类

linq - 组合多个表达式 (Expression<Func<T,bool>>) 不适用于变量。为什么?

c# - 表达式树 - 替换表达式

dynamic - 动态构建 lambda 表达式

c# - 如何在 C# 中使用表达式创建动态 lambda 连接查询?

c# - 直接类型转换与 'as' 运算符?

C# - 将枚举值列表转换为字符串列表

使用 ConfigureAwait(false) 的 C# async/await 链接

c# - 数据网格和列数

c# - 使用 lambda 表达式从 Controller 获取操作