Search code examples
.netxmlserializerdatacontractserializer

With .NET DataContractSerializer instance, can I check the Type that was passed into its constructor?


I'm specifically asking about DataContractSerializer, but this is also relevant to XmlSerializer

The constructors for these serializer types take a Type object as an argument, and each serializer instance can only serialize objects of this type.

Is there any way to later check this type? There are no obvious get properties or methods that do this.


I am ultimately trying to create an extension method on DataContractSerializer to simplify serializing objects as XML to in-memory strings.

For this extension method, checking the type isn't mission critical, but I think it would allow for clearer exception handling. If the check is left off the user will just get a SerializationException rather than an ArguemntException.

public static string WriteObjectToString(this DataContractSerializer serializer, object obj) {
    if (serializer == null) 
        throw new ArgumentNullException(nameof(serializer));
    if (obj == null) 
        throw new ArgumentNullException(nameof(obj));

    //---------------------------
    //This statement will not compile:
    if (serializer.TypeToSerialize != obj.GetType()) 
        throw new ArgumentException("Invalid type.");
    //---------------------------

    using (var output = new StringWriter())
    using (var writer = new XmlTextWriter(output)) {
        serializer.WriteObject(writer, obj);
        return output.GetStringBuilder().ToString();
    }        
}

A somewhat related question:

Is there a reason why DataContractSerializer (which was created after generics were introduced to .NET, unlike XmlSerializer) uses a Type object parameter rather than a generic type? Wouldn't it be simpler to have a DataContractSerializer{T} with methods like

  • void WriteObject(Stream, T)
  • T ReadObject(Stream)

Solution

  • Your first assumption is incorrect. DataContractSerializer can serialize different types of objects when you pass in knownTypes in its constructor. However, the resulting xml will use the first type name as its root xml element name.

    The sample code below should work:

    DataContractSerializer serializer = new DataContractSerializer(typeof(Foo), new Type[] {typeof(Bar), });
    Bar bar = new Bar();
    serializer.WriteObject(stream, bar);
    

    The resulting XML will look like this:

    <Foo><Bar>...</Bar></Foo>
    

    Hope this information will change your design, because it is not necessary to create a DataContractSerializer object per type. But it should explain why generic is not used with DataContractSerializer.