Wie kann man nicht serialisierbare Beobachter aus einem [serialisierbaren] InotifyPropertychanged -Implementierer ausschließen?

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

Frage

Ich habe fast hundert Entitätsklassen, die so aussehen:

[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));
    }
}

Beachten Sie die [field:NonSerialized] Attribut auf PropertyChanged. Dies ist notwendig, da einige Beobachter (in meinem Fall - ein Raster, das die Entitäten für die Ausgabe anzeigt) möglicherweise nicht serialisierbar ist, und die Entität muss serialisierbar sein, da sie durch Remoting bereitgestellt wird, von einer Anwendung, die auf einer Separatermaschine ausgeführt wird .

Diese Lösung funktioniert gut für triviale Fälle. Es ist jedoch möglich, dass einige Beobachter sind [Serializable], und müsste erhalten werden. Wie soll ich damit umgehen?

Lösungen, die ich nachdenke:

  • voll ISerializable - Benutzerdefinierte Serialisierung erfordert viel Code, ich würde es vorziehen, dies nicht zu tun
  • Verwendung [OnSerializing] und [OnDeserializing] Attribute zu serialisieren PropertyChanged manuell - aber diese Helfermethoden liefern nur SerializationContext, welches Afaik keine Serialisierungsdaten speichert (SerializationInfo macht das)
War es hilfreich?

Lösung

Sie haben Recht, dass die erste Option mehr Arbeit ist. Es kann Ihnen möglicherweise eine effizientere Implementierung bieten, aber es wird Ihre Entitäten stark erschweren. Beachten Sie das, wenn Sie eine Basis haben Entity Klasse, die implementiert ISerializable, Alle Unterklassen müssen auch die Serialisierung manuell implementieren!

Der Trick, die zweite Option für die Arbeit zu erhalten, besteht darin, das Ereignis weiterhin als nicht serialisierbar zu markieren, aber ein zweites Feld zu haben, das ist Serialisierbar und dass Sie sich während der entsprechenden Serialisierungshaken bevölkern. Hier ist ein Beispiel, das ich gerade geschrieben habe, um Ihnen zu zeigen, wie:

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;
            }
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top