views:

237

answers:

3

Given this code

        public override void Serialize(BaseContentObject obj)
    {
        string file = ObjectDataStoreFolder + obj.Slug + ".xml";
        if(obj.GetType() == typeof(Page))
        {
            DataContractSerializer dcs = new DataContractSerializer(typeof (Page));
            XmlDictionaryWriter myWriter =
                XmlDictionaryWriter.CreateTextWriter(new FileStream(file, FileMode.CreateNew, FileAccess.Write),
                                                 Encoding.UTF8);
            dcs.WriteObject(myWriter, obj);
            myWriter.Close();
        }
        else if(obj.GetType() == typeof(Image))
        {
            DataContractSerializer dcs = new DataContractSerializer(typeof (Image));
            ...
            ...
        }
    }

is there a way to do something like this

    DataContractSerializer dcs = new DataContractSerializer(obj.GetType()); // this fails however, compiler error

and get rid of those if() statements above? The constructor of DataContractSerializer there expects Type or Namespace but it does not work with obj.GetType().

My class hierarchy is as follows:

BaseContentClass (abstract)

Page (concrete, inherits BaseContentClass)

Image (concrete, inherits BaseContentClass)

...

?

A: 

If you are talking about this DataContractSerializer then the following code will compile fine:

DataContractSerializer dcs = new DataContractSerializer(obj.GetType());

As the constructor expects a type parameter.

Darin Dimitrov
I just tried it again in some other place and it does work indeed, so I really don't get it where did my error before come from. Thanks!
mare
+1  A: 

Tell the serializer what to anticipate:

[KnownType(typeof(Page))]
[KnownType(typeof(Image))]
[DataContract]
public abstract class BaseContentObject { /* ... */ }

[DataContract]
public class Page : BaseContentObject { /* ... */ }

[DataContract]
public class Image : BaseContentObject { /* ... */ }

Then you can use new DataContractSerializer(typeof(BaseContentObject )) for everything.

Marc Gravell
This looks interesting. However, on my abstract class I currently do not have [DataContract] attribute (only inheriting classes are decorated at the moment). Should I decorate abstract too?
mare
A: 

I would prefer to use generics. The helper can looks like:

public static string Serialize<T>(T t, IEnumerable<System.Type> types, bool preserveReferences)
    {
        StringBuilder aStringBuilder = new StringBuilder();
        using (StringWriter aStreamWriter = new StringWriter(aStringBuilder))
        {
            DataContractSerializer aDCS;
            using (XmlTextWriter aXmlTextWriter = new XmlTextWriter(aStreamWriter))
            {
                aDCS = new DataContractSerializer( typeof( T ), types, int.MaxValue, false, preserveReferences, null );

                aDCS.WriteObject(aXmlTextWriter, t);
            }
        }
        return aStringBuilder.ToString();
    }

Generics will allow you to serialize any type you want without using if statements.

kosto