So, this is getting into the nuts and bolts, but I am hoping someone here may have an insight.
Here's what I have managed to gather (though, of course, I could be wrong about any of it, so please correct me)
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.
Expression.Assign
Is a method that creates a BinaryExpression that represents an assignment operation
Here's my questions: Why cant we just use Expression.Assign when supplying bindings to the Expression.MemberInit method? Instead of:
MemberAssignment binding = Expression.Bind(PropAccessMethodInfo, TargetExpression)
For example, we could just do the following:
MemberExpression getProperty = Expression.Property(FindObjectExpression, PropAccessMethodInfo)
Expression binding = Expression.Assign(getProperty, TargetExpression)
I know that the compiler will complain, but I guess I am asking if there is more than a syntactic issue here. Put another way, does Expression.Bind / MemberBindings give us something additional under the hood? Or, are they just syntactic sugar that makes it easier to manage member intializations?
Even more specifically, could it in anyway help keep track of the relationship between business objects and the underlying entities in .NET EF4? Does it somehow fit into "Working with Proxies" in the Entity Framework or help with change tracking or the bridge between the business object and the EF-based data-access layer?
As you can probably foresee, I am trying to programmatically wire the creation of my business objects from the underlying component Entities and such expressions (especially, the MemberInit method) can help with the creation bit for sure.
However, I was unsure if the EF / .NET is smart enough to use those bindings to do tracking? Or, whether I could reuse those same bindings to the Biz<->Ent tracking / bridge.
I hope that made sense. If something is unclear, I'd be happy to give more information.
Thanks!!
A Binding contains all the information that can be shared across several BindingExpression objects. A BindingExpression is an instance expression that cannot be shared and that contains all the instance information about the Binding.
Bind(MemberInfo, Expression) Creates a MemberAssignment that represents the initialization of a field or property. Bind(MethodInfo, Expression) Creates a MemberAssignment that represents the initialization of a member by using a property accessor method.
An expression in C# is a combination of operands (variables, literals, method calls) and operators that can be evaluated to a single value. To be precise, an expression must have at least one operand but may not have any operator.
The object initializer is a complex syntactic sugar... It's only syntactic sugar because at the IL level there isn't anything resembling an object initializer... There are no special instructions... Only the C# compiler writes the instructions in a certain order, but the same code could be written without using the OI. Sadly rarely the exact working of this sugar is described.
And now I'll show you why it's complex syntactic sugar!
You could think that this:
foo = new Foo { Bar = 5 };
is translated to
foo = new Foo();
foo.Bar = 5;
But in truth you know that it isn't... Let's say that foo
is a property... Surely it isn't accessed twice (one write for saving the new Foo()
and one read for accessing foo.Bar
)...
So the code could/should be equal to this:
Foo tmp = new Foo();
foo = tmp;
tmp.Bar = 5;
but in truth it isn't! It's probably more similar to
Foo tmp = new Foo();
tmp.Bar = 5;
foo = tmp;
The difference is that if the setter of Foo.Bar
throws an exception, foo
isn't setted!
You can try it at: http://ideone.com/PjD7zF
The source code:
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);
}
}
This not-so-suble difference, added to the complexity of the syntactic sugar, is surely more than enough to create a "special" Expression
that is built only for this (the Expression.MemberInit
).
The Expression.Bind
is then necessary, because they wanted to simulate exactly the working of the object initializer, and in the object initializer you don't have access to the "this" of the new object. You can't write:
// wrong
foo = new Foo { this.Bar = 5 };
and they didn't want you to be able to write expressions like
foo = new Foo { somethingElse.Prop = 10 }
that would be possible if the Expression.MemberInit
simply accepted an array of Expression.Assign
.
Second point... Expression.MemberInit
is in .NET 3.5 (and it's necessary because member initialization is something quite used in LINQ), Expression.Assign
is only in .NET 4.0. Expression trees were born and built for LINQ (at least the LINQ minus the LINQ to Objects, because the LINQ to Objects doesn't use Expression trees). Expression.Assign
wasn't necessary so it wasn't implemented. Expression.MemberInit
was necessary, so it was implemented.
Third point... member initialization is something quite common in LINQ, so having to build all the expressions from the "base" parts of the member initialization (a temporary variable, some assignments, ...) was surely more difficult (and these expressions when debugged were surely more complex) than having a pre-built method "all-in-one".
Fourth point... LINQ providers normally don't implement all the possible Expression
(s), and quite often have to work with the fact that the expression will be executed in remote on a completely different environment (see for example LINQ-to-SQL that executes LINQ queries on an SQL Server). Expression.MemberInit
is much more limited than Expression.Assign
, so it is easier to implement by a LINQ provider.
So choose some of these reasons... They are all quite good, and probably any one of them alone would be enough to decide to implement an Expression.MemberInit
. Four of them together?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With