2017-01-27 2 views
1

Что было бы самым простым способом сериализации и десериализации только объявленных типов свойств, игнорируя тот факт, что фактический объект более выведен, чем объявлен? Например, с этими классами:Как сериализовать/десериализовать только свойства базового класса с помощью DataContractSerializer?

[DataContract] 
public class Base 
{ 
    [DataMember] 
    string BaseProperty { get; set; } 
} 

public class Derived : Base 
{ 
    string DerivedProperty { get; set; } 
} 

Я хотел бы быть в состоянии достичь эквивалент этого:

Base baseObject = new Derived(); 
var baseSerializer = new DataContractSerializer(typeof(Base)); 

using (var fileStream = File.OpenWrite("file")) 
using (var writer = XmlDictionaryWriter.CreateBinaryWriter(fileStream)) 
{ 
    baseSerializer.WriteObject(writer, baseObject); 
} 

using (var fileStream = File.OpenRead("file")) 
using (var reader = XmlDictionaryReader.CreateBinaryReader(fileStream, new XmlDictionaryReaderQuotas())) 
{ 
    var deserialized = (Base)baseSerializer.ReadObject(reader); 
} 

Предоставлено пример кода не удается, потому что Derived не известного типа, конечно. Но мне не интересно писать дополнительную информацию в файл, только то, что предоставляет базовый класс.

+0

Не нужно ли добавлять «KnownTypeAttribute» где-нибудь? https://msdn.microsoft.com/en-us/library/system.runtime.serialization.knowntypeattribute(v=vs.110).aspx – Michael

+0

Я знаю, что это можно заставить работать, просто добавив 'Derived' в список известных типов. Но я явно не хочу этого делать. Я хочу игнорировать тот факт, что фактический объект не является простой «базой». –

+0

XmlDictionaryWriter имеет тенденцию сохранять информацию о типе. Просто используйте сериализаторы без поддержки типа по умолчанию, например JSON. В Newtonsoft.JSON вы можете указать контракт на сериализацию, в котором вы указываете, что сериализовать и что не должно быть вообще. – eocron

ответ

2

Это решение использует отражение, чтобы захватить свойства базового класса и задает новый экземпляр значений базового класса для значений производного класса. Он решает вашу текущую проблему, но может не решить все проблемы.

Удачи, это весело программировать, и я уверен, что вам придется это изменить!

[DataContract] 
    public class Base 
    { 
     [DataMember] 
     string BaseProperty { get; set; } 

     public void SetBase(string val) 
     { 
      BaseProperty = val; 
     } 
    } 

    public class Derived : Base 
    { 
     public Derived() 
     { 
      SetBase("TestWorks"); 
     } 

     string DerivedProperty { get; set; } 
    } 

    static void Main(string[] args) 
    { 
     var obj = new Derived(); 

     Base baseObject = GetBaseObject<Base, Derived>(obj); 

     var baseSerializer = new DataContractSerializer(typeof(Base)); 

     using (var fileStream = File.OpenWrite("file")) 
     using (var writer = XmlDictionaryWriter.CreateBinaryWriter(fileStream)) 
     { 
      baseSerializer.WriteObject(writer, baseObject); 
     } 

     using (var fileStream = File.OpenRead("file")) 
     using (var reader = XmlDictionaryReader.CreateBinaryReader(fileStream, new XmlDictionaryReaderQuotas())) 
     { 
      var deserialized = (Base)baseSerializer.ReadObject(reader); 
     } 
    } 

    public static TBase GetBaseObject<TBase, T>(T obj) where TBase : new() where T : TBase 
    { 
     TBase bObj = new TBase(); 

     var bProps = bObj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); 

     foreach (var bProp in bProps) 
     { 
      bProp.SetValue(bObj, 
       obj.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) 
       .First(p => p.Name == bProp.Name).GetValue(obj)); 
     } 

     return bObj; 
    } 
Смежные вопросы