expression.bind和expression.assign之间有什么区别(或者:MemberBinding的特殊

本文关键字:expression 或者 MemberBinding 区别 bind assign 之间 什么 | 更新日期: 2023-09-27 18:26:20

所以,这是一个细节,但我希望这里的人能有所了解。

以下是我设法收集到的(当然,我可能对其中任何一个都错了,所以请纠正我)

Expression.Bind

根据我的研究,包括[topic][1]上的MSDN条目,Expression.Bind方法似乎用于生成MemberAssignment类型的表达式,MemberAssignment是MemberBinding表达式的特定子类型。该方法接受MemberInfo和它应该绑定到的表达式。生成的MemberAssignment表达式表示成员的初始化。

表达式.Assign

是一种创建BinaryExpression的方法,该方法表示分配操作

以下是我的问题:为什么我们不能在为Expression.MemberInit方法提供绑定时只使用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中业务对象和底层实体之间的关系?它在某种程度上符合";使用代理";在实体框架中,或者帮助进行更改跟踪,或者在业务对象和基于EF的数据访问层之间架起桥梁?

正如你可能预见到的那样,我正试图通过编程将我的业务对象的创建与底层组件实体联系起来,而这样的表达式(尤其是MemberInit方法)无疑可以帮助创建。

然而,我不确定EF/.NET是否足够聪明,可以使用这些绑定进行跟踪?或者,我是否可以重用与Biz&lt->Ent跟踪/桥接。

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

谢谢!!

expression.bind和expression.assign之间有什么区别(或者:MemberBinding的特殊

对象初始值设定项是一个复杂的语法糖。。。这只是语法上的糖,因为在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);
    }
}

这种不那么细微的差异,加上句法糖的复杂性,肯定足以创建一个仅为此而构建的"特殊"ExpressionExpression.MemberInit)。

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

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

他们不想让你写这样的表达式

foo = new Foo { somethingElse.Prop = 10 } 

如果CCD_ 9简单地接受CCD_。

第二点。。。Expression.MemberInit在.NET 3.5中(这是必要的,因为成员初始化在LINQ中非常常用),Expression.Assign仅在.NET 4.0中。表达式树是为LINQ生成的(至少是LINQ减去LINQ到对象,因为LINQ到目标不使用表达式树)。Expression.Assign不是必需的,所以没有实现。Expression.MemberInit是必要的,因此它得以实施。

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

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

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

相关文章: