按照规范,我们写一个包含事件的类应该这样(以PropertyChanged事件为例):
Code
public class User : INotifyPropertyChanged
{
/// <summary>
/// Name of user.
/// </summary>
private string _name;
/// <summary>
/// Gets or sets the name of user.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged (this, new PropertyChangedEventArgs ("Name"));
}
}
}
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Called when property changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
protected virtual void OnPropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (null != PropertyChanged)
{
PropertyChanged (sender, e);
}
}
}
public class User : INotifyPropertyChanged
{
/// <summary>
/// Name of user.
/// </summary>
private string _name;
/// <summary>
/// Gets or sets the name of user.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged (this, new PropertyChangedEventArgs ("Name"));
}
}
}
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Called when property changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
protected virtual void OnPropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (null != PropertyChanged)
{
PropertyChanged (sender, e);
}
}
}
这里OnPropertyChanged方法的作用是确保当没有人订阅事件时,不会调用一个空的委托而引发异常,并且实现了对派生类重写事件处理的支持。
然而,很多时候对于一些简单类型,比如上面这样一个贫血类型,根本不会有复杂的继承体系,这时,我们可以这样简化:
Code
public sealed class User : INotifyPropertyChanged
{
/// <summary>
/// Name of user.
/// </summary>
private string _name;
/// <summary>
/// Gets or sets the name of user.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
PropertyChanged (this, new PropertyChangedEventArgs ("Name"));
}
}
}
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
public sealed class User : INotifyPropertyChanged
{
/// <summary>
/// Name of user.
/// </summary>
private string _name;
/// <summary>
/// Gets or sets the name of user.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
PropertyChanged (this, new PropertyChangedEventArgs ("Name"));
}
}
}
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
通过对PropertyChanged事件委托赋初值,保证了它不会是一个空的委托,因而可以放心调用。同时我也将这个类声明为sealed,保证其不会被继承。
这样写是不是简单很多?免去了无趣地写一个个OnEvent方法。但这只是个偷懒,而且不是个怎么好的偷懒,因为它会导致编程习惯的不一致,只有当你确定你写的类足够简单而且不会被继承时,才可以使用。
PS: 这个Trick我是从微软的P&P小组的代码中学来的。