SERIALIZABLE] inotifyPropertyChanged 구현 자에서 비 소생성 관찰자를 배제하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/618994

문제

나는 거의 수백 개의 엔티티 클래스가 다음과 같이 보입니다.

[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] 직렬화 할 속성 PropertyChanged 수동으로 - 그러나 이러한 도우미 방법은 만 제공합니다 SerializationContext, AFAIK은 직렬화 데이터를 저장하지 않습니다 (SerializationInfo 것을 수행)
도움이 되었습니까?

해결책

첫 번째 옵션은 더 많은 작업입니다. 잠재적으로보다 효율적인 구현을 제공 할 수 있지만 엔티티를 많이 복잡하게 할 것입니다. 기지가 있다면 고려하십시오 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;
            }
        }
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top