C# API中模型与它们的接口设计详解

2020-01-05 09:30:12王冬梅

实现属性变更通知最简单的办法是每次在调用属性设置器时触发它们。虽然从技术方面看是可行的,但仍有一些性能方面的影响。


public string Name
{
 get { return m_Name; }
 set
 {
 m_Name = value;
 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
 }
}

在上面的示例中,即使没有不存在任何侦听者,每个属性变更通知让然会分配一个新对象来保存属性名称。如果这些通知频繁发生,则可能会触发不必要的垃圾回收。为了避免这种情况,应该把PropertyChangedEventArgs对象缓存起来。

另一个问题是事件可能是不必要的。如果属性值实际上没有发生改变,就相当于无缘无故地触发屏幕重绘。所以我们需要做一个简单的检查:


static readonly PropertyChangedEventArgs NameProperty = new PropertyChangedEventArgs(nameof(Name));
public string Name
{
 get { return m_Name; }
 set
 {
 if (m_Name == value)
  return;
 m_Name = value;
 PropertyChanged?.Invoke(this, NameProperty);
 }
} 

这个过程可能非常繁琐,因此就有了“MVVM框架”,用来减少这些噪音。Get和Set方法与内部字典一起使用,用来维护状态。通过这种方式,可以为我们处理PropertyChangedEventArgs缓存和属性值变更改检查。具体细节会有所不同,但它们或多或少看起来像这个来自Tortuga Anchor的例子。


public string Name
{
 get => Get<string>();
 set => Set(value);
}

请注意,这种便利性可能会对性能造成一点影响。访问内部字典比使用字段慢,并且值的装箱操作可能会消除缓存PropertyChangedEventArgs所带来的收益。

如果你只编写服务器端代码,可能会想“我没有UI,所以我不需要这些”。如果真是这样,或许你是对的。但有时候使用INotifyPropertyChanged可以简化一些复杂的代码。我建议服务器端开发人员至少将其视为一种选择。