在关于将 MVVM 与 Xamarin 一起使用的 C# 教程中,我偶然发现了 MVVM 类中的以下序列:
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string PropertyName) {
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
作者建议对 PropertyChanged 进行空检查,调用它:
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
在什么情况下,属性变更可以为空?我的意思是,它不仅在上面声明了一行,没有声明它不会让代码编译,那么 PropertyChanged 怎么可能是空的呢?
通常其他类在声明public event whatever
的类上注册处理程序 - 只要没有类在您的PropertyChanged
命名的事件处理程序上注册其处理程序,它实际上是null
。
因此建议使用
PropertyChanged?.Invoke(...)
以避免出现空引用异常。
有关 MSDN 的文档:属性更改事件处理程序委托
读取事件处理:处理和引发事件
代码/用法:
using System;
using System.ComponentModel;
public class Program
{
public static void Main(string[] args)
{
C1 c1 = new C1(); // create instance of class that raises event
L1 l1 = new L1(); // create instance of 1st class that handles event
L2 l2 = new L2(); // create instande of 2nd class that handles event
// no handlers are yet registered on the event
try
{
c1.Raise(); // will crash and output exception as no handler set yet
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
c1.SafeRaise(); // safe, will print message
l1.AddListener(c1); // add as listener
c1.Raise(); // prints handled message
l2.AddListener(c1); // add 2nd listener
c1.Raise(); // both print handled message
Console.ReadLine(); // stop console from closing
}
// Has the prop-changed and 2 raise-methods, 1 safe, 1 not.
public class C1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// unsafe - will throw if not yet any listerer registered
public void Raise() =>
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(
DateTime.Now.ToString()));
// safe, even if no listener registered.
public void SafeRaise()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(
DateTime.Now.ToString()));
Console.WriteLine("PropertyHandlerNotSet! - but safe due to '"+
" PropertyChanged?.Invoke(this, new PropertyChanged"+
"EventArgs(DateTime.Now.ToString()));' ");
}
}
public class L1
{
public void AddListener(C1 c) => c.PropertyChanged += this.Handler;
public void Handler(object sender, PropertyChangedEventArgs e)
=> Console.WriteLine("L1: " + e.PropertyName);
}
public class L2
{
public void AddListener(C1 c) => c.PropertyChanged += this.Handler;
public void Handler(object sender, PropertyChangedEventArgs e)
=> Console.WriteLine("L2: " + e.PropertyName);
}
}
输出:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
PropertyHandlerNotSet! - but safe due to ' PropertyChanged?.Invoke(this, new Pro
pertyChangedEventArgs(DateTime.Now.ToString()));'
L1: 06.03.2018 23:03:50 // 1st raise after registering
L1: 06.03.2018 23:03:50 // 2nd raise after registering
L2: 06.03.2018 23:03:50
如果不看到完整的范围,很难分辨。但是,这里有几种可能性:
它被公开为公共
PropertyChanged
被标记为 public
,这意味着外部参与者可以将其设置为其他值,包括 null。即使成员是私有的,内部方法仍可能无法设置值。
它未分配
在代码段中,您不会指示是否为变量分配了值。如果按所示执行,它将为空。