Hon*_*dha 8 c# expression-trees
所以,这是进入细节,但我希望这里有人可能有洞察力.
这是我设法收集的内容(当然,我可能错了任何一个,所以请纠正我)
Expression.Bind
基于我的研究,包括[topic] [1]上的MSDN Entry,似乎Expression.Bind方法用于生成MemberAssignment类型的表达式,MemberAssignment是MemberBinding表达式的特定子类型.该方法采用MemberInfo和它应该绑定的表达式.生成的MemberAssignment表达式表示成员的初始化.
Expression.Assign
是一种创建表示赋值操作的BinaryExpression的方法
这是我的问题:为什么我们只能在提供Expression.MemberInit方法的绑定时使用Expression.Assign?代替:
MemberAssignment binding = Expression.Bind(PropAccessMethodInfo, TargetExpression)
Run Code Online (Sandbox Code Playgroud)
例如,我们可以执行以下操作:
MemberExpression getProperty = Expression.Property(FindObjectExpression, PropAccessMethodInfo)
Expression binding = Expression.Assign(getProperty, TargetExpression)
Run Code Online (Sandbox Code Playgroud)
我知道编译器会抱怨,但我想我在问这里是否还有一个语法问题.换句话说,Expression.Bind/MemberBindings会给我们一些额外的东西吗?或者,它们只是语法糖,使管理成员初始化更容易吗?
更具体地说,它是否可以帮助跟踪业务对象与.NET EF4中的底层实体之间的关系?它是否适合实体框架中的"使用代理"或帮助进行更改跟踪或业务对象与基于EF的数据访问层之间的桥梁?
正如您可能预见的那样,我正在尝试以编程方式从底层组件Entities连接我的业务对象的创建,这样的表达式(尤其是MemberInit方法)可以帮助确定创建位.
但是,我不确定EF/.NET是否足够聪明,可以使用这些绑定进行跟踪?或者,我是否可以将这些相同的绑定重用于Biz < - > Ent tracking/bridge.
我希望这是有道理的.如果有什么不清楚的地方,我很乐意提供更多信息.
谢谢!!
对象初始化器是一个复杂的语法糖......它只是语法糖,因为在IL级别没有任何类似于对象初始化器......没有特殊指令......只有C#编译器才能将指令写入某个但是,可以在不使用OI的情况下编写相同的代码.可悲的是,这种糖的确切工作很少被描述.
现在我会告诉你为什么它是复杂的语法糖!
你可以这样认为:
foo = new Foo { Bar = 5 };
Run Code Online (Sandbox Code Playgroud)
被翻译成
foo = new Foo();
foo.Bar = 5;
Run Code Online (Sandbox Code Playgroud)
但实际上你知道它不是......让我们说这foo是一个属性......当然它不会被访问两次(一次写入用于保存new Foo(),一次用于访问foo.Bar)...
所以代码可能/应该等于这个:
Foo tmp = new Foo();
foo = tmp;
tmp.Bar = 5;
Run Code Online (Sandbox Code Playgroud)
但实际上并非如此!它可能更类似于
Foo tmp = new Foo();
tmp.Bar = 5;
foo = tmp;
Run Code Online (Sandbox Code Playgroud)
不同之处在于,如果setter Foo.Bar抛出异常,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);
}
}
Run Code Online (Sandbox Code Playgroud)
这种不那么简单的差异,加上语法糖的复杂性,肯定足以创造一个Expression仅为此(the Expression.MemberInit)构建的"特殊" .
这Expression.Bind是必要的,因为他们想要精确模拟对象初始值设定项的工作,并且在对象初始值设定项中,您无法访问新对象的"this".你不能写:
// wrong
foo = new Foo { this.Bar = 5 };
Run Code Online (Sandbox Code Playgroud)
他们不希望你能写出像这样的表达式
foo = new Foo { somethingElse.Prop = 10 }
Run Code Online (Sandbox Code Playgroud)
如果Expression.MemberInit简单地接受一个数组,那将是可能的Expression.Assign.
第二点...... Expression.MemberInit在.NET 3.5中(并且它是必要的,因为成员初始化是在LINQ中使用的东西),Expression.Assign仅在.NET 4.0中.表达式树是为LINQ而生成和构建的(至少LINQ减去对象的LINQ,因为LINQ to Objects不使用表达式树).Expression.Assign没有必要,所以没有实施.Expression.MemberInit是必要的,所以它被实施了.
第三点......成员初始化在LINQ中非常常见,因此必须从成员初始化的"基础"部分(临时变量,某些赋值,......)构建所有表达式肯定更难(并且这些调试时的表达式肯定比使用预先构建的方法"all-in-one"更复杂.
第四点...... LINQ提供程序通常不会实现所有可能Expression的操作,并且经常需要处理表达式将在完全不同的环境中在远程执行的事实(请参阅例如LINQ-to-SQL在SQL Server上执行LINQ查询).Expression.MemberInit比限制更有限Expression.Assign,因此LINQ提供程序更容易实现.
因此,选择其中的一些原因......他们都是相当不错的,而且很可能他们中的任何一个单独就足以决定实施Expression.MemberInit.他们四个在一起?