التوافق المتماثل والخلفي
-
26-09-2019 - |
سؤال
لا بد لي من العمل تطبيقًا قديمًا يستخدم BinaryFormatter لتسلسل بيانات التطبيق في Filestream (على سبيل المثال في ملف يسمى "data.oldformat") دون أي تحسين ، تم تمييز الفئة الرئيسية مع السمة
<serializable()>public MainClass
.......
end class
ورمز التسلسل
dim b as new binaryformatter
b.serialize(mystream,mymainclass)
في محاولة لتحسين عملية التسلسل/إزالة التسلسل ، جعلت الفصل ببساطة ينفذ الواجهة القابلة للتطبيق وكتبت بعض إجراءات التسلسل الأمثل
<serializable()>public MainClass
implements ISerializable
.......
end class
يعمل التحسين بشكل جيد حقًا ، لكن يجب أن أجد طريقة لإعادة توزيع البيانات داخل الملفات القديمة للتوافق المتخلف.
كيف أقوم بذلك؟؟
بيرلويجي
المحلول
Stmax لديه إجابة ممتازة ، ومع ذلك أود تنفيذه مثل هذا ، والذي يستخدم SerializationEntry.GetEnumerator()
بدلاً من try/catch
. بهذه الطريقة أكثر نظافة وأسرع بكثير.
public MainClass(SerializationInfo info, StreamingContext context) {
int version = 0;
foreach (SerializationEntry s in info)
{
if (s.Name == "version")
{
version = (int)s.Value;
break;
}
}
switch (version) {
case 0:
// deserialize "old format"
break;
case 1:
// deserialize "new format, version 1"
break;
default:
throw new NotSupportedException("version " + version + " is not supported.");
}
}
أفضل إصدار LINQ باستخدام .firstordefault () ، لكن SerializationInfo لا ينفذ ienumerable - في وجهه ، بغرابة بما فيه الكفاية ، حتى أنه لا ينفذ الواجهة القديمة.
نصائح أخرى
نظرًا لأنك قمت بالفعل بتنفيذ واجهة Iserializable ، فمن المحتمل أيضًا أن تضيف بالفعل المُنشئ المطلوب:
public MainClass(SerializationInfo info, StreamingContext context) {}
يمكنك استخدام كائن Info-Object الذي تم تمريره إلى المُنشئ لاسترداد البيانات من الملف المسلسل. بشكل افتراضي (أي عند عدم تنفيذ عدم وجود غير قابل للتطبيق) ، يتم استخدام أسماء الحقول كمعرفات أثناء التسلسل. لذلك إذا كان لدى فصلك القديم حقل "int x" ، فيمكنك إلغاء تمييز هذا باستخدام:
this.x = info.GetInt32("x");
بالنسبة للإصدارات الأحدث ، عادةً ما أضيف إدخال "إصدار" أثناء التسلسل ، مثل هذا:
public void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue("version", 1);
info.AddValue("othervalues", ...);
}
أثناء التخلص من ذلك ، يمكنك التحقق من إدخال الإصدار هذا وتهتز وفقًا لذلك:
public MainClass(SerializationInfo info, StreamingContext context) {
int version;
try {
version = info.GetInt32("version");
}
catch {
version = 0;
}
switch (version) {
case 0:
// deserialize "old format"
break;
case 1:
// deserialize "new format, version 1"
break;
default:
throw new NotSupportedException("version " + version + " is not supported.");
}
}
لم أقم بتجميع هذا الرمز ، فقد يحتوي على أخطاء مطبعية.
امل ان يساعد.
فقط جرب نفس الشيء الذي كنت تفعله حتى الآن
BinaryFormatter b = new BinaryFormatter();
MainClass a = b.DeSerialize(mystream) as MainClass;
لم يغير تطبيق iserializable فصلك الأصلي ، لقد أضفت للتو بعض الطرق
عند تسلسل الكائنات ، قم بإضافة حقل إصدار إضافي (يجب ألا يضيف هذا الكثير من النفقات العامة). ثم في طريقة getObjectData الخاصة بك ، حاول استرداد حقل الإصدار أولاً وبناءً على ما إذا كان هذا موجودًا أم لا (عن طريق اصطياد SerializationException) ، قم بتسليم الطريق القديم أو الطريقة الجديدة. سيكون للطريقة القديمة تسلسل جميع البيانات ، لذا يجب أن تكون قادرًا على الاتصال ... لجميع الحقول.
يجب أن يعمل الرمز السابق الخاص بك. هل تحصل على استثناء؟ حاول استخدام مُنشئ جديد:
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)