Reputation: 807
Here is my list of classes:-
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; }
}
below is the method which is trying to serialize the objects created of the above classes:-
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();
}
As you can see I even used the attribute [Serializable] but still getting the error that I cant serialize interfaces.
Also I just want serialize the objects of the given classes and not interfaces.
Upvotes: 0
Views: 300
Reputation: 29222
See the comments at the end. My first solution answers the question directly but I don't recommend doing it unless you have no choice. Short version - I recommend solving the problem by using the concrete types Author
, Category
, and Publisher
instead of interfaces in the Book
class.
In order to serialize a type there must be some way of determining what the concrete types of the members are. It's possible that something could serialize an instance of Book
using an implementation of IUniquelyIdentifiable
that is unknown to the application deserializing it.
You can modify your Book
class like this:
[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; }
}
Then use a DataContractSerializer
to serialize. Here's an example:
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);
}
}
This answers the question, but it doesn't solve any problems. In fact, it creates a new problem.
If you just declare the Author
, Category
, and Publisher
properties of Book
as concrete types, then you're constrained to using those types. The compiler will show an error if you try to set that property using any class that isn't Author
.
But if you add the KnownType
attribute as above, the problem is even worse because it's hidden. Now you can set Author
to anything implementing IUniquelyIdentifiable
. But when you do that (perhaps in some other part of your application) you have no way of knowing that it will fail when serialized. The constraint is still there - you still have to use Author
. The difference is that now you get a runtime exception instead of a compile error.
You could instead specify a list of known types to the DataContractSerializer
. That gives you a way to specify more types, even using reflection to get a list of types that implement the interface.
But it's still problematic. It's a hidden constraint. You're saying that the type of the property is IUniquelyIdentifiable
. According to proper OOP design and the Liskov substitution principle you should be able to use any implementation of that interface. But in reality you can't use any implementation. You have to use one that may or may not be labeled as a "known" type somewhere else (or in multiple places) in your code. Someone could break your application at any time without causing a compile error.
Based on that I'd say to only use the above methods if you have no choice, like if you have to serialize something that you didn't design. If you're writing your own classes then I would just declare Book
using the concrete types Author
, Category
, and Publisher
.
Upvotes: 2
Reputation: 1525
You can't serialize interfaces. It doesn't work. your solution is to change Book's properties to the actual serializable classes:
[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; }
}
The question @Richard_Everett linked contain the same answer. Sorry I can't provide any better solution.
Upvotes: 1