C#事件:定义:如何可以为空?
在一篇关于将MVVM与Xamarin.Forms结合使用的C#教程中,我在MVVM类中偶然发现了以下序列:C#事件:定义:如何可以为空?,c#,event-handling,undefined,C#,Event Handling,Undefined,在一篇关于将MVVM与Xamarin.Forms结合使用的C#教程中,我在MVVM类中偶然发现了以下序列: public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged(string PropertyName) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(PropertyName));
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string PropertyName) {
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
作者建议对PropertyChanged执行空检查,并调用它:
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
在哪些情况下,PropertyChanged可以为空?我的意思是,它不仅在上面声明了一行,不声明它不会让代码编译,那么PropertyChanged怎么可能是空的呢?通常,其他类会在声明公共事件的类上注册它们的处理程序,无论什么
——只要没有类在您的PropertyChanged
命名事件处理程序上注册它的处理程序,它实际上就是空的
因此,建议使用
PropertyChanged?.Invoke(...)
以避免获取NullRef异常
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。即使成员是私有的,内部方法也可能无法设置该值
未分配它
在代码段中,您不指示是否为变量赋值。如果如图所示执行,它将为空。声明它并不意味着分配它。空检查是所有事件(委托)的一般准则。在您自己的示例中为空!你试过了吗?我想没有。正如@DourHighArch所说的,你已经在你的帖子里。。。你能澄清一下为什么你认为帖子中的代码没有显示“在什么情况下可以将财产更改为空”@Dour&Alexei:我在问之前试过了,不管有没有检查,都有效,相信我。该代码是Xamarin表单项目的一部分。对不起,我没有提到这一点,因为我认为这不相关。据我所知,在Xamarin.Forms项目中,这个事件总是由Xamarin.Forms库订阅的,因此在Xamarin生态系统中它永远不会为空。然而,检查是一种良好的做法。我会相应地修改我的问题文本。好的,我想我明白了。我对如何声明和调用事件处理程序的看法刚刚转变了180度:-),以确定我是否真的理解了它:。。。如果此代码与Xamarin.Forms库链接,该库具有PropertyChangedEventHandler事件的处理程序,那么PropertyChanged是否会获得非空值?如果是-如果多个库具有PropertyChangedEventHandler怎么办?编译器会拒绝这个,还是所有的处理程序都会尝试激活?@Nimral-请参阅代码。@Nimral我不知道Xamarin,现在主要做WPF。您可以注册多个处理程序,并以无序方式“同时”通知所有处理程序。所有人都可以根据自己的意愿处理引发的事件。声明后,事件可以由我自己的代码调用,并通知Xamarin.Forms绑定成员已更改了值。然后,Xamarin将更新屏幕上的值。我还没有深入研究事件处理程序,现在我已经阅读了关于“委托模型”和“观察者模式”的基础知识,这些东西都很到位。