C# 如何序列化属性声明为接口的类?

C# 如何序列化属性声明为接口的类?,c#,oop,serialization,interface,C#,Oop,Serialization,Interface,以下是我的课程列表:- public interface IUniquelyIdentifiable { string AuthorName { get; set; } } public interface IUniquelyIdentifiable1 { string CategoryName { get; set; } } public interface IUniquelyIdentifiable2

以下是我的课程列表:-

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; }
    }
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();
        } 
下面是尝试序列化上述类创建的对象的方法:-

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; }
    }
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();
        } 
如您所见,我甚至使用了属性[Serializable],但仍然得到了无法序列化接口的错误


另外,我只想序列化给定类的对象,而不是接口。

不能序列化接口。它不起作用。 您的解决方案是将Book的属性更改为实际的可序列化类:

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

问题@Richard_Everett链接包含相同的答案。很抱歉,我无法提供更好的解决方案。

您无法序列化接口。它不起作用。 您的解决方案是将Book的属性更改为实际的可序列化类:

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

问题@Richard_Everett链接包含相同的答案。很抱歉,我无法提供更好的解决方案。

请参阅最后的评论。我的第一个解决方案直接回答了这个问题,但我不建议你这样做,除非你别无选择。简短版本-我建议使用具体类型
Author
Category
Publisher
来解决问题,而不是使用
Book
类中的接口


为了序列化类型,必须有某种方法来确定成员的具体类型。使用反序列化应用程序未知的
iuniquelyidentification
实现对
Book
的实例进行序列化是可能的

您可以像这样修改
书籍
类:

[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; }
}
然后使用
DataContractSerializer
进行序列化。下面是一个例子:

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

这回答了问题,但并不能解决任何问题。事实上,它带来了一个新问题

如果您只是将
书籍
作者
类别
出版商
属性声明为具体类型,那么您只能使用这些类型。如果您试图使用非
作者
的任何类设置该属性,编译器将显示错误

但是如果像上面那样添加
KnownType
属性,问题会更严重,因为它是隐藏的。现在,您可以将
Author
设置为实现
iUniquelyIdentification
的任何内容。但是当您这样做时(可能在应用程序的其他部分中),您无法知道序列化时它会失败。约束仍然存在-您仍然必须使用
Author
。不同之处在于,现在您得到的是运行时异常,而不是编译错误

您可以将已知类型的列表指定给
DataContractSerializer
。这为您提供了一种指定更多类型的方法,甚至可以使用反射来获得实现接口的类型列表

但这仍然是个问题。这是一个隐藏的约束。您是说属性的类型是
i唯一可识别的
。根据适当的OOP设计和Liskov替换原则,您应该能够使用该接口的任何实现。但实际上,您不能使用任何实现。您必须在代码中的其他地方(或多个地方)使用一个可能标记为“已知”类型的类型,也可能不标记为“已知”类型。有人可以随时中断您的应用程序,而不会导致编译错误


基于此,我想说,如果你没有选择,只使用上面的方法,比如如果你必须序列化一些你没有设计的东西。如果您正在编写自己的类,那么我只需使用具体类型
Author
Category
Publisher
来声明
Book
,请参见结尾的注释。我的第一个解决方案直接回答了这个问题,但我不建议你这样做,除非你别无选择。简短版本-我建议使用具体类型
Author
Category
Publisher
来解决问题,而不是使用
Book
类中的接口


为了序列化类型,必须有某种方法来确定成员的具体类型。使用反序列化应用程序未知的
iuniquelyidentification
实现对
Book
的实例进行序列化是可能的

您可以像这样修改
书籍
类:

[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; }
}
然后使用
DataContractSerializer
进行序列化。下面是一个例子:

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

这回答了问题,但并不能解决任何问题。事实上,它带来了一个新问题

如果您只是将
书籍
作者
类别
出版商
属性声明为具体类型,那么您只能使用这些类型。如果您试图使用非
作者
的任何类设置该属性,编译器将显示错误

但是如果像上面那样添加
KnownType
属性,问题会更严重,因为它是隐藏的。现在,您可以将
Author
设置为实现
iUniquelyIdentification
的任何内容。但是当您这样做时(可能在应用程序的其他部分中),您无法知道序列化时它会失败。约束仍然存在-您仍然必须使用
Author
。不同之处在于,现在您得到的是运行时异常,而不是编译错误

您可以将已知类型的列表指定给
DataContractSerializer
。这为您提供了一种指定更多类型的方法,甚至可以使用反射来获得实现接口的类型列表

但这仍然是个问题。这是一个隐藏的约束。您是说属性的类型是
i唯一可识别的
。根据适当的OOP设计和Liskov替换原则,您应该能够使用该接口的任何实现。但实际上,您不能使用任何实现。