typesafe NotifyPropertyChanged с использованием выражений linq
Форма Создайте свой собственный MVVM У меня есть следующий код, который позволяет нам делать безопасные типы вызовов NotifyOfPropertyChange:
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);
}
Как этот подход сравнивается со стандартным подходом простых строк с точки зрения производительности? Иногда у меня есть свойства, которые меняются с очень высокой частотой. Могу ли я использовать этот безопасный подход? После первых тестов это, кажется, имеет небольшое значение. Какую нагрузку на ЦП и память потенциально может вызывать этот подход?
6 ответов
Как выглядит код, который вызывает это? Я предполагаю, что это что-то вроде:
NotifyOfPropertyChange(() => SomeVal);
что неявно:
NotifyOfPropertyChange(() => this.SomeVal);
который делает захват this
, и в значительной степени означает, что дерево выражений должно быть построено (с Expression.Constant
) с нуля каждый раз. А потом разбираешь это каждый раз. Таким образом, накладные расходы определенно нетривиальны.
Это слишком много, хотя? Это вопрос, на который только вы можете ответить, с профилированием и знанием вашего приложения. Он считается нормальным для большого использования MVC, но это (в общем случае) не вызывает его в длительном замкнутом цикле. Вы должны профилировать против желаемой цели производительности, в основном.
У Эмиеля Джонгериуса хорошее сравнение производительности различных реализаций INotifyPropertyChanged.
http://www.pochet.net/blog/2010/06/25/inotifypropertychanged-implementations-an-overview/
Суть в том, что если вы используете INotifyPropertyChanged для привязки данных в пользовательском интерфейсе, то различия в производительности разных версий незначительны.
Как насчет использования стандарта defacto
if (propName == value) return;
propName = value;
OnPropertyChanged("PropName");
а затем создайте пользовательский инструмент, который проверяет и реорганизует файл кода в соответствии с этим стандартом. Этот инструмент может быть заданием перед сборкой, также на сервере сборки. Просто, надежно, выполняет.
Безопасность типов и отсутствие потери производительности: расширение NotifyPropertyWeaver. Он автоматически добавляет все уведомления перед компиляцией...
Я использую следующий метод в базовом классе, реализующем INotifyPropertyChanged, и это так просто и удобно:
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);
}
Я надеюсь, что вы найдете это полезным также.:-)
Прогулка по стеку идет медленно, а лямбда-выражение еще медленнее. У нас есть решение, похожее на хорошо известное лямбда-выражение, но почти такое же быстрое, как строковый литерал. См. http://zamboch.blogspot.com/2011/03/raising-property-changed-fast-and-safe.html