如何从 INotifyPropertyChanged实现者中排除不可序列化的观察者?

我有近百个实体类看起来像这样:

[Serializable] public class SampleEntity : INotifyPropertyChanged { private string name; public string Name { get { return this.name; } set { this.name = value; FirePropertyChanged("Name"); } } [field:NonSerialized] public event PropertyChangedEventHandler PropertyChanged; private void FirePropertyChanged(string propertyName) { if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } 

注意PropertyChanged上的[field:NonSerialized]属性。 这是必要的,因为一些观察者(在我的情况下 – 显示版本实体的网格)可能不是可序列化的,并且实体必须是可序列化的,因为它是通过远程处理由分离器机器上运行的应用程序提供的。 。

此解决方案适用于琐碎的案例。 但是,某些观察者可能是[Serializable] ,并且需要保留。 我该怎么处理?

正在考虑的解决方案:

  • 完全ISerializable – 自定义序列化需要编写大量代码,我宁愿不这样做
  • 使用[OnSerializing][OnDeserializing]属性手动序列化PropertyChanged – 但这些辅助方法只提供SerializationContext ,AFAIK不存储序列化数据( SerializationInfo这样做)

你是对的,第一个选择是更多的工作。 虽然它可以为您提供更高效的实现,但它会使您的实体复杂化很多。 考虑一下,如果你有一个实现ISerializable的基本Entity类, 所有子类也必须手动实现序列化

让第二个选项起作用的技巧是继续将事件标记为不可序列化,但要使第二个字段序列化并在适当的序列化挂钩期间填充自己。 这是我刚刚写的一个示例,向您展示如何:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var entity = new Entity(); entity.PropertyChanged += new SerializableHandler().PropertyChanged; entity.PropertyChanged += new NonSerializableHandler().PropertyChanged; Console.WriteLine("Before serialization:"); entity.Name = "Someone"; using (var memoryStream = new MemoryStream()) { var binaryFormatter = new BinaryFormatter(); binaryFormatter.Serialize(memoryStream, entity); memoryStream.Position = 0; entity = binaryFormatter.Deserialize(memoryStream) as Entity; } Console.WriteLine(); Console.WriteLine("After serialization:"); entity.Name = "Kent"; Console.WriteLine(); Console.WriteLine("Done - press any key"); Console.ReadKey(); } [Serializable] private class SerializableHandler { public void PropertyChanged(object sender, PropertyChangedEventArgs e) { Console.WriteLine(" Serializable handler called"); } } private class NonSerializableHandler { public void PropertyChanged(object sender, PropertyChangedEventArgs e) { Console.WriteLine(" Non-serializable handler called"); } } } [Serializable] public class Entity : INotifyPropertyChanged { private string _name; private readonly List _serializableDelegates; public Entity() { _serializableDelegates = new List(); } public string Name { get { return _name; } set { if (_name != value) { _name = value; OnPropertyChanged("Name"); } } } [field:NonSerialized] public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { var handler = PropertyChanged; if (handler != null) { handler(this, e); } } protected void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } [OnSerializing] public void OnSerializing(StreamingContext context) { _serializableDelegates.Clear(); var handler = PropertyChanged; if (handler != null) { foreach (var invocation in handler.GetInvocationList()) { if (invocation.Target.GetType().IsSerializable) { _serializableDelegates.Add(invocation); } } } } [OnDeserialized] public void OnDeserialized(StreamingContext context) { foreach (var invocation in _serializableDelegates) { PropertyChanged += (PropertyChangedEventHandler)invocation; } } } }