Search code examples
c#c#-4.0lambdaextension-methodsexpression-trees

How this code works for handling INotifyPropertyChanged


I see below code in this link : An elegant way to implement INotifyPropertyChanged

I'm new to Expression Tree.can any one please explane how this code work simply?

thanks

private string _name;
public string Name
{
   get { return _name; }
   set { PropertyChanged.ChangeAndNotify(ref _name, value, () => Name); }
}

public static bool ChangeAndNotify<T>(this PropertyChangedEventHandler handler,ref T field, T value, Expression<Func<T>> memberExpression)
    {
        if (memberExpression == null)
        {
            throw new ArgumentNullException("memberExpression");
        }
        var body = memberExpression.Body as MemberExpression;
        if (body == null)
        {
            throw new ArgumentException("Lambda must return a property.");
        }
        if (EqualityComparer<T>.Default.Equals(field, value))
        {
            return false;
        }

        var vmExpression = body.Expression as ConstantExpression;
        if (vmExpression != null)
        {
            LambdaExpression lambda = Expression.Lambda(vmExpression);
            Delegate vmFunc = lambda.Compile();
            object sender = vmFunc.DynamicInvoke();

            if (handler != null)
            {
                handler(sender, new PropertyChangedEventArgs(body.Member.Name));
            }
        }

        field = value;
        return true;
    }

Solution

  • An expression tree is an object-oriented representation of an expression at runtime. The C# compiler can automatically write a limited subset of expressions as Expression<> instances, via a lambda - i.e.

    Func<string> anonMethod = () => "abc"; // this is a delegate
    Expression<Func<string>> expression = () => "abc"; // this is an expression
    

    The above will have a ConstantExpression; your example will have a ConstantExpression that captures this and a MemberExpression that wraps that constant (this) and the member (.Name). Then at runtime, it locates the MemberExpression, which has a MemberInfo, which has a Name. It could even have a ConstantExpression to a capture class, a MemberExpression to this (as a field on the capture-class), and then a MemberExpression to .Name.

    The difference is subtle, but an expression can be pulled apart and inspected at runtime - which is critical for LINQ. However: while the compiler can write these, they are not free to inspect; they have cost too.

    IMO, perhaps stick with:

    public string Name
    {
       get { return _name; }
       set { SomeSimpleNotifyMethod(ref _name, value, this, "Name"; }
    }
    

    this is simpler and faster (obviously, changing the method to take a string that it passes to the event).