开发者

How this code works for handling INotifyPropertyChanged

开发者 https://www.devze.com 2023-03-23 03:18 出处:网络
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?

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 C开发者_如何学JAVAhangeAndNotify<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;
    }


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).


Here's an extension method that is able to determine sender and property name just by inspecting lambda expression tree and without any major performance impact:

public static class PropertyChangedExtensions
{
    public static void Raise(this PropertyChangedEventHandler handler, Expression<Func<object>> property)
    {
        if (handler == null)
            return;

        var boxingExpr = property.Body as UnaryExpression;

        var memberExpr = (MemberExpression)(boxingExpr == null ? 
            property.Body : boxingExpr.Operand);

        var propertyName = memberExpr.Member.Name;
        var sender = ((ConstantExpression)memberExpr.Expression).Value;
        handler.Invoke(sender, new PropertyChangedEventArgs(propertyName));
    }
}

and usage is the same as you have right now:

public string Name
{
    get { return name; }
    set
    {
        name = value;
        PropertyChanged.Raise(() => Name);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号