Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between expression.bind and expression.assign (or: what is special about MemberBinding)

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!!

like image 934
HoneyBuddha Avatar asked Aug 05 '13 07:08

HoneyBuddha


People also ask

What is binding expressions?

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.

What is Bind method in C#?

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.

What is Expression C#?

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.


Video Answer


1 Answers

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?

like image 80
xanatos Avatar answered Oct 04 '22 12:10

xanatos