typesafe NotifyPropertyChanged using linq expressi

2019-01-11 21:07发布

问题:

Form Build your own MVVM I have the following code that lets us have typesafe NotifyOfPropertyChange calls:

public void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property)
{
    var lambda = (LambdaExpression)property;
    MemberExpression memberExpression;
    if (lambda.Body is UnaryExpression)
    {
        var unaryExpression = (UnaryExpression)lambda.Body;
        memberExpression = (MemberExpression)unaryExpression.Operand;
    }
    else memberExpression = (MemberExpression)lambda.Body;
    NotifyOfPropertyChange(memberExpression.Member.Name);
 }

How does this approach compare to standard simple strings approach performancewise? Sometimes I have properties that change at a very high frequency. Am I safe to use this typesafe aproach? After some first tests it does seem to make a small difference. How much CPU an memory load does this approach potentially induce?

回答1:

What does the code that raises this look like? I'm guessing it is something like:

NotifyOfPropertyChange(() => SomeVal);

which is implicitly:

NotifyOfPropertyChange(() => this.SomeVal);

which does a capture of this, and pretty-much means that the expression tree must be constructed (with Expression.Constant) from scratch each time. And then you parse it each time. So the overhead is definitely non-trivial.

Is is too much though? That is a question only you can answer, with profiling and knowledge of your app. It is seen as OK for a lot of MVC usage, but that isn't (generally) calling it in a long-running tight loop. You need to profile against a desired performance target, basically.



回答2:

Emiel Jongerius has a good performance comparrison of the various INotifyPropertyChanged implementations.

http://www.pochet.net/blog/2010/06/25/inotifypropertychanged-implementations-an-overview/

The bottom line is if you are using INotifyPropertyChanged for databinding on a UI then the performance differences of the different versions is insignificant.



回答3:

How about using the defacto standard

if (propName == value) return;
propName = value;
OnPropertyChanged("PropName");

and then create a custom tool that checks and refactors the code file according to this standard. This tool could be a pre-build task, also on the build server. Simple, reliable, performs.



回答4:

Stack walk is slow and lambda expression is even slower. We have solution similar to well known lambda expression but almost as fast as string literal. See http://zamboch.blogspot.com/2011/03/raising-property-changed-fast-and-safe.html



回答5:

I use the following method in a base class implementing INotifyPropertyChanged and it is so easy and convenient:

public void NotifyPropertyChanged()
    {
        StackTrace stackTrace = new StackTrace();

        MethodBase method = stackTrace.GetFrame(1).GetMethod();

        if (!(method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
        {
            throw new InvalidOperationException("The NotifyPropertyChanged() method can only be used from inside a property");
        }

        string propertyName = method.Name.Substring(4);

        RaisePropertyChanged(propertyName);
    }

I hope you find it useful also. :-)



回答6:

Typesafe and no performance loss: NotifyPropertyWeaver extension. It adds in all the notification automatically before compiling...