I've got a C# structure of classes with an abstract base class and various classes derived from this abstract class.
[System.Xml.Serialization.XmlInclude(typeof(B))]
public abstract class A {
...
}
[Serializable]
[XmlType("typename")]
public class B : A {
...
}
Furthermore, I'm using an instance of class B within another class C as a field with its abstract type like this:
public class C {
...
public A myItem { get; set; } //A is actually of type B
...
}
Now, when I serialize my class C via the standard xmlserializer, I get a XML structure like this:
<C>
<myItem p2:type="typename" xmlns:p2="...">
... //Fields as elements and stuff
</myItem>
</C>
But thats not what I need because I send those serialized C objects to a REST Webservice (which has no valid schema yet). What I actually need is something like this:
<C>
<typename>
... //Fields as elements and stuff
</typename>
</C>
But as you can see above, the xmlserializer seems to prefer the instance field name over the type name set via XmlType. Also, obviously I can't just use XmlElement("typename") for my field in C, because I don't know which concrete implementation of my abstract class A the field will contain.
Has anyone ever had a similar problem and could provide me with a solution to this? Or do i really need to implement IXmlSerializable in my class A and thus within all of my concrete A-derived classes to get this working?
EDIT: Just found out while reading some articles that IXmlSerializable doesn't let me control the wrapper element, so do I actually need to implement the Interface in class C with some sort of switch() on the type of the myItem member?
Thanks for your help!
Best regards,
flo
Okay, seems I have found the solution, at least for serialization, don't know yet if this also works for deserialization. The key is a special constructor for the XMLElement attribute, which allows to specify the key to use if a abstract type is used:
http://msdn.microsoft.com/en-us/library/cz6bdh5z.aspx
Maybe this is also helpful to someone else.
Best,
flo
For deserialization you will need to provide the XmlSerializer with all the types that it MAY encounter in all the abstract typed properties.
The XmlSerializer has a specific constructor in which you can feed it a collection of Types.
Related
In my application I use a list of objects implementing my ISorter interface with exposes a single method void Sort(MyClass myClass)
So far ive created this list at the entry point on my application with a hardcoded set of ISorter implementations. Now im at the point where I'd like to be able to save and load this list from file.
I'd like the format to be XML so that it can be hand edited, but i discovered that .NET XMLSerializer class cannot serialize Interfaces. It can serialize a list of base classes, providing I mark the baseclass with the appropriate attributes:
[System.Xml.Serialization.XmlInclude(typeof(MyClassA))]
[System.Xml.Serialization.XmlInclude(typeof(MyClassB))]
class MyBaseClass
I dislike this, as it clutters my class with xml specific attributes, when i may wish to replace xml serialization with a different storage method later.
What is the downside to replacing my ISort interface with a SortBase baseclass, to facilitate serialziation? Is the use of an interface here wrong to begin with? Should i keep the interface, but implement it using a SortBase class from which all my other classes derive?
How could I abstract the storage so that the storage implementation could be changed later, and avoid decorating my classes with xml attributes?
Any additional information on best practices pertaining to datastorage/loading would be helpful
EDIT: The idea is that a user can create an text file (atm XML is preferred) specifying sorting operations which can the be loaded and applied to the data set.
EDIT2: I have, simplified, this situation
class Foo{
List<ISorter> MySorters
}
interface ISorter{
void Sort(MyClass myClass)
}
class SortByColor : ISorter{
public string SomeColorProperty{get;set;}
void Sort(MyClass myClass)
}
class SortByName: ISorter{
public string SomeNameProperty{get;set;}
void Sort(MyClass myClass)
}
Id like to pass my List to some storage/loading method which can create/load the list from some underlaying datasource ( for example an XML file)
EDIT3:
Ill probably end up using DataContractserializer, or XMLSerializer as this solves my issue, as long as i provide a common base class. I had expected there to be some more elegant way this could be handled, without polluting my objects with attributes
I was trying to create an attribute that implies [Serializable] but I noticed that this SerializableAttribute class is sealed.
In Java it was possible to create an interface (say, MyInterface) that is inherited from Serializable interface and so all the subclasses of MyInterface would also be serializable, even its sub-sub classes would be so.
Let's say I am creating an ORM and I want customers to annotate their entity classes as [DatabaseEntity] but in order to make sure that entities are serializable, I also need to ask them to attribute their classes with extra [Serializable] which does not look quite compact and neat.
I am wondering why SerializableAttribute class is sealed and why has Inherited=false which implies that subclasses of serializable class will not be serializable unless it is explicitly stated. What motives are behind these design choices?
The SerializableAttribute is only used by the BinaryFormatter. If you are writing your own serialiser then don't worry about.
The sealed keyword is applied to the attribute not the class associated with the attribute. It is saying that the SerializableAttribute cannot be subclassed.
The BinaryFormatter uses an opt-in model. Any class (or subclass) must specify that it is serializable. This why the Inherited=false is used.
It's suggested best practice that all .Net attributes should be sealed, according to Microsoft:
The .NET Framework class library provides methods for retrieving custom attributes. By default, these methods search the attribute inheritance hierarchy; for example System.Attribute.GetCustomAttribute searches for the specified attribute type, or any attribute type that extends the specified attribute type. Sealing the attribute eliminates the search through the inheritance hierarchy, and can improve performance. [my emphasis]
So [Serializable] is sealed because it's quicker for .Net reflection to check the attributes. The cost is that you can't inherit and extend SerializableAttribute.
You can make your own un-sealed attributes if you want (you'll get code analysis warnings though).
This gets a little confusing with how attributes are used in inheritance for the classes that they apply to. It's probably best to use an example:
[Serializable]
public class A
{
public int SimpleSerialisableProperty { get; set;}
}
public class B : A
{
public C ComplexReferenceProperty { get; set; }
}
[Serializable]
public class D : A
{
public bool AnotherSerialisableProperty { get; set;}
}
You asked why SerializableAttribute.Inherited = false and this is why:
Class A is marked as [Serializable], and it is.
However class B inherits A and extends it with properties that are not serialisable. If .Net tries to serialise B it will encounter an error.
That Inherited = false tells .Net that just because A has been marked as [Serializable] not every class that inherits it will be serialisable too.
Now class D inherits A and is serialisable, so it gets its own [Serializable] attribute.
Finally, in terms of design attributes are a great way of extending behaviour (nice UI editors in property grids, etc). However they are terrible at enforcing it. If you need your customers to implement their entity classes in a particular way then an abstract base class or an interface is a much better way to go. If you make it an attribute then you're basically letting them know that [Serializable] is an option that you can handle either way.
Serialization is not a magic thing and you don't need any attribute to serialize an object. It is a process of writing your class' properties and fields to a stream (and attributes are only directives to serializers about how to behave while outputting an object).
See this over-simplified serializer code which totally ignores all attributes including NonSerializable
object obj = yourObject;
var props = obj.GetType()
.GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(obj, null));
string serializedText = String.Join("\n",
props.Select(kv => kv.Key + "=" + kv.Value ?? kv.Value.ToString()));
Above code, for example, would give
IsEmpty=False
X=3
Y=5
for object obj = new Point(3,5);
Deserialization process would be to read these values and set the properties back accordingly.
Put the [Serializable] attribute on top of the class you want serialized. Serialization is opt-in process. You have to manually do that for each class you want serialized. There are bunch of other keywords.
I have around 50 classes in polymorphic, inheritance relation. I used XmlSerializer to serialize them. Now for few classes I want to implement IXmlSerializable. So I started for one of class.This class not base class but derived directly from base class of all polymorphic relation.
After implementation, resultant XML contains tags only for above class which I have written in WriteXML method. There is no information for other classes. Very strange behavior!!!!
So please guide me to solve this issue, so that other classes information would maintain.
As I understand you correct - your xml contains properties that you implicit add in WriteXML (of current class)? But it is correct behavior. You should implicit add item as in example in description of interface.
If you need properties of base classes - add them. if you need properties of classes that inherit from this class - try to get them via reflection. Get Property Names using Reflection . But instead of typeof(MyClass) use .GetType() and check there how to get properties values.
Similar questions here and there.
End the ReadXml(XmlReader reader) method with the line
reader.Read();
seams to solves the problem...
I'm currently using an XMLSerializer to serialize a list of a class of my own. One of the class's properties is an instance of a sealed class that does not have a parameterless constructor, so the XML Serializer refuses to serialize the class. How can I get around this? I need that property to be serialized.
Is there some way for me to specify how that class should be serialized?
We'd like to stay with XML; is there another XML serializer that I could use that would not have this problem?
Again, I apologize if this is a dupe, but I had no idea what to search.
[EDIT] To clarify, I don't have access to the source of the sealed class.
It's not possible to do directly; XmlSerializer can't cope with classes that don't have a parameterless constructor.
What I normally do is wrap the parameterless class in another class that's compatible with XML. The wrapper class has a parameterless constructor and a set of read-write properties; it has a FromXml method that calls the real class's constructor.
[XmlIgnore]
public SomeClass SomeProperty { get; set; }
[XmlElement("SomeProperty")]
public XmlSomeClass XmlSomeProperty
{
get { return XmlSomeClass.ToXml(SomeProperty); }
set { SomeProperty = value.FromXml(); }
}
Can you make a private parameterless constructor? That will work assuming you have access to the class's code.
You can implement ISerializable on the containing class, then implement a custom serializer.
Depending on the complexity of the xml, you might have some luck with DataContractSerializer. This doesn't offer anything like the same level of xml control, but it bypasses the constructor completely. And works for private types.
I might also ask: does it actually need to be xml? There are other serializers for things like json or protobuf that don't have the XmlSerializer limitations.
Use IXmlSerializable, XmlSerializer is too limited.
I am working on a ASP.NET application that has a class that inherits a List of a Custom Object.
public class UserRoleList : List<UserRoleBO> {
public UserRoleList() { }
}
How do I make this class serializable in C#?
I believe you really just need to ensure that UserRoleBO is serializable and the list will take care of itself. This assumes the values you want to serialize are public properties on the UserRoleBO and UserList. For more info see What is the point of the ISerializable interface?
You need to do the following
Ensure UserRoleList is serializable
Ensure UserRoleBO is serializable
Ensure the type of all fields inside UserRoleBO are serializable (this is recursive)
The easiest way to do this is to add the [Serializable] attribute to the classes. This will work in most cases.
On a different note, deriving from List<T> is usually speaking a bad idea. The class is not meant to be derived from and any attempt to specialize it's behavior can be thwarted in sceanarios where the derived class is used from a List<T> reference. Can you explain why you want to derive in this way? There is likely a more robust solution.
Like so:
[Serializable]
public class UserRoleList : List<UserRoleBO> {
public UserRoleList() { }
}
(Note the 'Serializble' tag will need to be on all classes that need to be serialised (so the parent as well.
And then use BinarySerialization to do it.