كيفية استبعاد المراقبين غير القابلة للتطبيق من تطبيق inotifyPropertyChanged [Serializable]؟
-
03-07-2019 - |
سؤال
لدي ما يقرب من مائة من فصول الكيانات تبدو هكذا:
[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;
}
}
}
}