如何从 [Serializable] INotifyPropertyChanged 实现者中排除不可序列化的观察者?
Posted
技术标签:
【中文标题】如何从 [Serializable] INotifyPropertyChanged 实现者中排除不可序列化的观察者?【英文标题】:How to exclude nonserializable observers from a [Serializable] INotifyPropertyChanged implementor? 【发布时间】:2010-10-11 18:21:17 【问题描述】:我有将近一百个看起来像这样的实体类:
[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
这样做)
【问题讨论】:
【参考方案1】:你是对的,第一个选项是更多的工作。虽然它可能会为您提供更有效的实施,但它会使您的实体复杂化很多。考虑一下,如果您有一个实现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<Delegate> _serializableDelegates;
public Entity()
_serializableDelegates = new List<Delegate>();
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;
【讨论】:
invocation.Target 可以为空(对于匿名委托),请务必检查这一点 这些事件对 XmlSerializer 没有影响(我很好,我只需要远程处理)。 OnSerializing 和 OnDeserialized 应该是私有的,不需要暴露它们。 _serializableDelegates 可以在 OnDeserialized 和 OnSerialized 中清除以减少内存使用(而不是在 OnSerializing 中清除)。 我必须记住反序列化的对象图包含新对象,旧的引用不再起作用。哦!以上是关于如何从 [Serializable] INotifyPropertyChanged 实现者中排除不可序列化的观察者?的主要内容,如果未能解决你的问题,请参考以下文章
如何克服“A non-serializable value detection”
从 Android 中的对象实现 Serializable 和 Parcelable 接口 - 冲突
混合 MarshalByRefObject 和 Serializable
使用 Serializable - AndroidX 将数据从 RecyclerView 传递到 RecyclerViewMore