2016-08-09 107 views
0

Hier ist meine Liste der Klassen: -Wie serialisiert ich eine Klasse mit Eigenschaften, die als Schnittstellen deklariert sind?

public interface IUniquelyIdentifiable 
    { 
     string AuthorName { get; set; } 
    } 
    public interface IUniquelyIdentifiable1 
    { 
     string CategoryName { get; set; } 

    } 
    public interface IUniquelyIdentifiable2 
    { 
     string PublisherName { get; set; } 
    } 

    [Serializable] 
    public class Book 
    { 
     //BookId, Category, Title, Author, Publisher, Description, Price, ISBN, PublicationDate. 
     public IUniquelyIdentifiable Author { get; set; } 
     public IUniquelyIdentifiable1 Category { get; set; } 
     public IUniquelyIdentifiable2 Publisher { get; set; } 
     public int BookId { get; set; } 
     public string Title { get; set; } 
     public string Description { get; set; } 
     public int ISBN { get; set; } 
     public int Price { get; set; } 
     public string PublicationDate { get; set; } 
    } 

    [Serializable] 
    class Author : IUniquelyIdentifiable 
    { 
     //AuthorId, AuthorName, DateOfBirth, State, City, Phone 
     public int AuthorId { get; set; } 
     public string AuthorName { get; set; } 
     public string DateOfBirth { get; set; } 
     public string State { get; set; } 
     public string City { get; set; } 
     public int Phone { get; set; } 
    } 

    [Serializable] 
    class Category : IUniquelyIdentifiable1 
    { 
     //CategoryId, CategoryName, Description 
     public int CategoryId { get; set; } 
     public string CategoryName { get; set; } 
     public string Description { get; set; } 
    } 

    [Serializable] 
    class Publisher : IUniquelyIdentifiable2 
    { 
     //PublisherId, PublisherName, DateOfBirth, State, City, Phone. 
     public int PublisherId { get; set; } 
     public string PublisherName { get; set; } 
     public string DateOfBirth { get; set; } 
     public string State { get; set; } 
     public string City { get; set; } 
     public int Phone { get; set; } 
    } 

unten ist die Methode, die die Objekte der obigen Klassen erstellt zu serialisiert versucht: -

public static void XmlSerializeMyObject() 
     { 

      XmlSerializer writer = new XmlSerializer(typeof(Book)); 
      //overview.title = "Serialization Overview"; 
      var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//SerializationOverview.xml"; 
      FileStream file = File.Create(path); 
      writer.Serialize(file,bookList); 
      file.Close(); 
     } 

Wie Sie habe ich auch das sehen Attribut [Serializable] aber immer noch den Fehler, dass ich Schnittstellen nicht serialisieren kann.

Auch ich möchte nur die Objekte der angegebenen Klassen und nicht Schnittstellen serialisieren.

+0

Mögliches Duplikat von [Serialisierungsschnittstellen] (http://stackoverflow.com/questions/4659248/serializing-interfaces) –

+1

Nein ist es nicht. Diese Frage ist nicht geschlossen. Es hat nicht einmal eine richtige Antwort. Bitte überprüfen Sie diese richtig, bevor Sie Fragen stellen. –

+0

versuchen Sie mit DataContract Serializer https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx – Thorarins

Antwort

2

Siehe die Kommentare am Ende. Meine erste Lösung beantwortet die Frage direkt, aber ich empfehle es nicht, es sei denn, Sie haben keine Wahl. Kurze Version - Ich empfehle, das Problem zu lösen, indem Sie die Betonarten Author, Category und Publisher anstelle von Schnittstellen in der Klasse Book verwenden.


Um einen Typ serialisieren zu können, muss es einen Weg geben, zu bestimmen, was die konkreten Typen der Mitglieder sind. Es ist möglich, dass etwas eine Instanz von Book unter Verwendung einer Implementierung von IUniquelyIdentifiable serialisieren kann, die der Deserialisierung der Anwendung unbekannt ist.

Sie können Ihre Book Klasse wie folgt ändern:

[Serializable][DataContract][KnownType(typeof(Author))] 
[KnownType(typeof(Category))] 
[KnownType(typeof(Publisher))] 
public class Book 
{ 
    [DataMember]public IUniquelyIdentifiable Author { get; set; } 
    [DataMember]public IUniquelyIdentifiable1 Category { get; set; } 
    [DataMember]public IUniquelyIdentifiable2 Publisher { get; set; } 
    [DataMember]public int BookId { get; set; } 
    [DataMember]public string Title { get; set; } 
    [DataMember]public string Description { get; set; } 
    [DataMember]public int ISBN { get; set; } 
    [DataMember]public int Price { get; set; } 
    [DataMember]public string PublicationDate { get; set; } 
} 

Dann ein DataContractSerializer verwenden zu serialisiert. Hier ein Beispiel:

using (var sw = new StringWriter()) 
{ 
    using (var xw = new XmlTextWriter(sw)) 
    { 
     var book = new Book(); 
     book.Author = new Author { AuthorName = "Bob" }; 
     book.Category = new Category { CategoryId = 5 }; 
     book.Publisher = new Publisher { City = "Clearwater" }; 
     var serializer = new DataContractSerializer(typeof(Book)); 
     serializer.WriteObject(xw, book); 
     var output = sw.ToString(); 
     Assert.IsNotNull(sw); 
    } 
} 

Dies beantwortet die Frage, aber es löst nicht alle Probleme. In der Tat schafft es ein neues Problem.

Wenn Sie einfach die Author, Category und Publisher Eigenschaften von Book als konkrete Typen deklarieren, dann sind Sie gezwungen, diese Typen zu verwenden. Der Compiler zeigt einen Fehler an, wenn Sie versuchen, diese Eigenschaft mit einer beliebigen Klasse zu setzen, die nicht Author ist.

Aber wenn Sie das KnownType Attribut wie oben hinzufügen, ist das Problem noch schlimmer, weil es versteckt ist. Nun können Sie Author auf alles setzen, was IUniquelyIdentifiable implementiert. Aber wenn Sie das tun (vielleicht in einem anderen Teil Ihrer Anwendung), haben Sie keine Möglichkeit zu wissen, dass es bei der Serialisierung scheitern wird. Die Einschränkung ist immer noch da - Sie müssen nochAuthor verwenden. Der Unterschied besteht darin, dass Sie jetzt eine Laufzeitausnahme anstelle eines Kompilierungsfehlers erhalten.

Sie können stattdessen eine Liste bekannter Typen für die DataContractSerializer angeben.Das gibt Ihnen eine Möglichkeit, weitere Typen anzugeben, sogar mithilfe von Reflektion, um eine Liste von Typen zu erhalten, die die Schnittstelle implementieren.

Aber es ist immer noch problematisch. Es ist eine versteckte Einschränkung. Sie sagen, dass der Typ der Eigenschaft IUniquelyIdentifiable ist. Gemäß dem richtigen OOP-Design und dem Liskov-Substitutionsprinzip sollten Sie in der Lage sein, eine beliebige Implementierung dieser Schnittstelle zu verwenden. In Wirklichkeit können Sie jedoch keine Implementierung verwenden. Sie müssen einen verwenden, der möglicherweise an anderer Stelle (oder an mehreren Stellen) in Ihrem Code als "bekannter" Typ gekennzeichnet ist. Jemand könnte Ihre Anwendung jederzeit abbrechen, ohne einen Kompilierungsfehler zu verursachen.

Darauf basierend würde ich sagen, nur die oben genannten Methoden zu verwenden, wenn Sie keine Wahl haben, wie wenn Sie etwas serialisieren müssen, das Sie nicht entworfen haben. Wenn Sie Ihre eigenen Klassen schreiben, würde ich einfach Book mit den konkreten Typen Author, Category und Publisher deklarieren.

+0

Hey Scott, Anfangs habe ich nur die Betontypen benutzt. Aber wie du oben sehen kannst benötige ich nur ein Datenfeld aus den Klassen Autor, Herausgeber und Kategorie. Kannst du mir helfen, herauszufinden, wie das geht? –

+0

Sie könnten einfach einen 'AuthorName' in die' Book' Klasse als String setzen. Ich habe festgestellt, dass die Schnittstellen Namen als eindeutige Bezeichner verwenden. Ich würde empfehlen, eine Klasse wie 'AuthorId' zu erstellen, die nur die Eigenschaften enthält, die benötigt werden, um einen Autor zu identifizieren und diese in' Book' anstatt einer Zeichenkette oder eines int zu verwenden. Siehe [diese Blogpost] (http://scotthannen.org/blog/2016/03/26/define-types-instead-of-using-primitives.html). –

1

Sie können keine Schnittstellen serialisieren. Es funktioniert nicht. Ihre Lösung des Buches Eigenschaften zu den tatsächlichen serializable Klassen zu ändern:

[Serializable] 
public class Book 
{ 
    //BookId, Category, Title, Author, Publisher, Description, Price, ISBN, PublicationDate. 
    public Author Author { get; set; } 
    public Category Category { get; set; } 
    public Publisher Publisher { get; set; } 
    public int BookId { get; set; } 
    public string Title { get; set; } 
    public string Description { get; set; } 
    public int ISBN { get; set; } 
    public int Price { get; set; } 
    public string PublicationDate { get; set; } 
} 

Die Frage @Richard_Everett verknüpft enthalten die gleiche Antwort. Entschuldigung, ich kann keine bessere Lösung anbieten.

+1

Es stimmt, dass Sie keine Schnittstellen serialisieren können. Aber * Sie können * als Schnittstellen deklarierte Member serialisieren, wenn Sie den 'DataContractSerializer' verwenden und die Typen identifizieren, die die Schnittstellen darstellen können, indem Sie das' KnownType'-Attribut verwenden. –