代码之家  ›  专栏  ›  技术社区  ›  skolima

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

  •  12
  • skolima  · 技术社区  · 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));
        }
    }
    

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

    此解决方案适用于一般情况。然而,有些观察员可能是 [Serializable] ,并须予以保存。我该怎么处理?

    • 满的 ISerializable -自定义序列化需要编写大量代码,我不希望这样做
    • [OnSerializing] [OnDeserializing] 财产变更 手动-但是那些助手方法只提供 SerializationContext ,AFAIK不存储序列化数据( SerializationInfo
    1 回复  |  直到 17 年前
        1
  •  12
  •   Tim Cooper    14 年前

    Entity 实现的类 ISerializable , 所有子类还必须手动实现序列化 !

    让第二个选项工作的诀窍是继续将事件标记为不可序列化,但要有第二个字段

    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;
                }
            }
        }
    }
    
    推荐文章