2017-01-27 3 views
1

Was wäre die einfachste Art der Serialisierung und Deserialisierung nur der deklarierten Typen von Eigenschaften, wobei die Tatsache ignoriert wird, dass das tatsächliche Objekt mehr abgeleitet als deklariert ist? Zum Beispiel mit den folgenden Klassen:Wie serialisiert/deserialisiert nur Basisklasseneigenschaften mit DataContractSerializer?

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

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

würde Ich mag das Äquivalent dieses Ziel zu erreichen in der Lage sein:

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

bereitgestellt Beispielcode schlägt fehl, da Derived kein bekannter Art ist, natürlich. Aber ich bin nicht daran interessiert, diese zusätzlichen Informationen in eine Datei zu schreiben, nur was die Basisklasse bietet.

+0

Müssen Sie 'KnownTypeAttribute' nicht irgendwo hinzufügen? https://msdn.microsoft.com/en-us/library/system.runtime.serialization.knowntypeattribute(v=vs.110).aspx – Michael

+0

Ich weiß, dass dies funktioniert, indem man einfach 'Derived' zu der Liste hinzufügt von bekannten Typen. Aber ich will das explizit nicht machen. Ich möchte die Tatsache ignorieren, dass das eigentliche Objekt keine einfache Basis ist. –

+0

XmlDictionaryWriter neigt dazu, Typinformationen zu speichern. Verwenden Sie einfach Serialisierer ohne Standardunterstützung, z. B. JSON. In Newtonsoft.JSON können Sie einen Serialisierungsvertrag angeben, in dem Sie angeben, was serialisiert werden soll und was nicht generell sein soll. – eocron

Antwort

2

Diese Lösung verwendet Reflektion zum Abrufen der Eigenschaften der Basisklasse und legt eine neue Instanz der Basisklassenwerte für die abgeleiteten Klassenwerte fest. Es löst Ihr aktuelles Problem, löst aber möglicherweise nicht alle Probleme.

Viel Glück, das ist der Spaß am Programmieren und ich bin sicher, dass Sie dies ändern müssen!

[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; 
    } 
Verwandte Themen