- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
所以,这是进入细节和 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.MemberInit
比 Expression.Assign
限制更多,因此更容易由 LINQ 提供程序实现。
所以选择这些原因中的一些...它们都很好,可能其中任何一个单独都足以决定实现一个Expression.MemberInit
.四个在一起?
关于c# - expression.bind 和 expression.assign 之间有什么区别(或 : what is special about MemberBinding),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18052448/
我正在尝试构建模板类 Fod template class Fod { ... }; 它将包含一个带有 static const int value 的内部类 At指示模板参数的索引(S0 为 0,S
我很难理解 Python in a Nutshell 的最后一部分(粗体) Per-Instance Methods An instance can have instance-specific bi
我需要密码字段的正则表达式。 要求是: 密码长度必须在8到20个字符之间 必须包含至少一个字母和一个数字以及来自!@#$%^&*() 的特殊字符_+。 不应以特殊字符开头 我试过了 ^(?=.*[a-
我有一个 C 类型的输入字段。 PARAMETERS lv_sep TYPE c. 字段 lv_sep 应该只接受特殊字符。 你能帮助我如何给出这个约束吗? 最佳答案 您可以在 AT-SELECTIO
我记得 PaulP 展示了一个很酷的技巧来缩写重复的长 @specialized序列,但我找不到原来的帖子了。就像我有 trait Foo[@specialized(Int, Float, Doubl
我有一个特征和一个实现,如下所示: trait Foo[A] { def bar[B >: A: Ordering]: Foo[B] } class FooImpl[A]( val a: A, v
在Sas9中,如何用下划线替换我选择的所有,\ /或空格以及其他特殊字符?无论是在数据步骤中还是在宏函数中的解决方案都可以解决问题,我只是在寻找一种实现方法。 谢谢 最佳答案 您可以使用SAS内置的P
SPECIALIZE 的目的pragma 是创建更具体的函数版本。 我有一个功能 adaptBlocks :: Int -> BlocksField a -> Maybe (BlocksField a
我尝试使用 gcc 10 -std=gnu++20 -fconcepts 构建以下内容: template class MyClass{ T a; }; template class MyClas
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭11 年前。 Improve th
在哪里可以找到文件名中允许的字符列表(取决于操作系统)?(例如,在 Linux 上,文件名中允许使用字符 :,但在 Windows 上则不允许) 最佳答案 您应该从 Wikipedia Filenam
我有下面的powershell功能 Function Test { Param ( [Parameter()] [strin
我有下面的powershell功能 Function Test { Param ( [Parameter()] [strin
我有两个方阵 A 和 B。它们的每一项都有 1 或 0。示例如下所示 A channel id a b c 1 1 1 1 2 1 0 1 3 1 0 0 B id cha
是否可以将基础对象“特化”为派生对象? 例如: class base{... base(...) : ... {}//both have their own constructors virt
我有两个像这样连接在一起的圆圈: 我在形状内部有一个点,我想从该点沿一个方向将光线转换到形状上。为了检索形状边缘的类型转换位置。 我的第一个想法是将 2 段连接到 2 个圆圈进行光线转换。如果没有成功
在我的 Java 项目中,我有以下类/接口(interface)层次结构: public interface ProductSearcher { Set search(String reque
是否可以在不引入与实现完全匹配的签名的情况下定义这个专门的重载? on(eventName: string, cb: Function); on(eventName: "view", cb: (arg
偶然发现 def foo(f: Int => Unit) {} def foo(f: Long => Unit) {} 由于 method foo is defined twice 无法编译.我知道上
在下面的例子中,为什么 foo(f)叫暧昧? 我知道第二个重载也适用于 P == () , 但为什么第一个不被认为更专业, 因此更好的匹配? func foo(_ f: () -> R) { prin
我是一名优秀的程序员,十分优秀!