如何序列化具有声明为接口的属性的类
本文关键字:接口 属性 声明 序列化 | 更新日期: 2023-09-27 18:01:25
以下是我的课程列表:-
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] ,但仍然得到错误,我不能序列化接口。
我还想序列化给定类的对象,而不是接口。
见文末注释。我的第一个解决方案直接回答了这个问题,但我不建议你这么做,除非你别无选择。短版本-我建议使用具体类型Author
, Category
和Publisher
来解决问题,而不是使用Book
类中的接口。
为了序列化一个类型,必须有某种方法确定成员的具体类型是什么。有可能某些东西可以使用IUniquelyIdentifiable
的实现来序列化Book
的实例,而应用程序对其反序列化是未知的。
你可以这样修改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);
}
}
这回答了问题,但没有解决任何问题。事实上,它产生了一个新问题。
如果您只是将Book
的Author
, Category
和Publisher
属性声明为具体类型,那么您将被限制使用这些类型。如果你试图使用非Author
的类设置该属性,编译器将显示错误。
但是如果像上面那样添加KnownType
属性,问题就更严重了,因为它是隐藏的。现在您可以将Author
设置为实现IUniquelyIdentifiable
的任何内容。但是当您这样做时(可能在应用程序的其他部分),您无法知道它在序列化时是否会失败。约束仍然存在- 仍然必须使用 Author
。不同之处在于,现在得到的是运行时异常,而不是编译错误。
您可以指定一个已知类型的列表给DataContractSerializer
。这为您提供了一种指定更多类型的方法,甚至可以使用反射来获得实现该接口的类型列表。
但它仍然是有问题的。这是一个隐藏的约束。你说属性的类型是IUniquelyIdentifiable
。根据适当的OOP设计和Liskov替代原则,您应该能够使用该接口的任何实现。但实际上你不能使用任何实现。您必须在代码的其他地方(或多个地方)使用可能被标记为"已知"类型的类型,也可能不标记为"已知"类型。有人可以在任何时候破坏你的应用程序而不会导致编译错误。
基于此,我想说只有在你别无选择的情况下才使用上述方法,比如你必须序列化一些不是你设计的东西。如果你正在编写自己的类,那么我将使用具体类型Author
, Category
和Publisher
来声明Book
。
不能序列化接口。这行不通。您的解决方案是将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包含相同的答案。对不起,我不能提供更好的解决方案。