C# 事件:定义:如何为 NULL



在关于将 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。即使成员是私有的,内部方法仍可能无法设置值。

它未分配

在代码段中,您不会指示是否为变量分配了值。如果按所示执行,它将为空。

最新更新