Nick Tarasov
Nick Tarasov

Reputation: 101

Serialize/deserialize System.RuntimeType

I've got a List of Types that I need to save to file and read it after. I use DataContractSerializer but I get an exception during deserialization:

Can't find constructor with arguments (SerializationInfo, StreamingContext) in ISerializable "System.RuntimeType".

I've added System.RuntimeType as a known type to my serializer, but it didn't help.

Here's code of my two methods

public static void SaveTypes(List<Type> types, string fileName)
{
    Type rt = types[0].GetType();

    List<Type> knownTypes = new List<Type>() { rt }; //I get a List with System.RuntimeType item here
    DataContractSerializer serializer = new DataContractSerializer(typeof(List<Type>), knownTypes);
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    Stream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
    using (XmlWriter xw = XmlWriter.Create(fs, settings))
        serializer.WriteObject(xw, types);
}

Serialization seems to work fine, and the output file is ok, but problem starts on deserializing:

    public static object LoadTypes(string fileName)
    {
        Stream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        byte[] data = new byte[file.Length];
        file.Read(data, 0, (int)file.Length);

        Type rt = file.GetType();
        List<Type> knownTypes = new List<Type>() { rt.GetType() };
        DataContractSerializer deserializer = new DataContractSerializer(typeof(List<Type>), knownTypes);

        Stream stream = new MemoryStream();
        stream.Write(data, 0, data.Length);
        stream.Position = 0;
        return deserializer.ReadObject(stream); //exception here
    }

Is there any way to go through this? Or maybe there's some other way to store types?

Upvotes: 7

Views: 2547

Answers (1)

Philip Pittle
Philip Pittle

Reputation: 12295

Marc Gravell is right, you probably should be serializing the data and not the types.

But for some reason, if you really want to serialize the types themselves, then you shouldn't serialize the Type object (pretty sure it's not serailizable). Anyway, serialize Type.FullName instead. When you load the Types, use Type.Load

public static void SaveTypes(IEnumerable<Type> types, string filename)
{
    using (var fs = File.Open(filename, FileMode.OpenOrCreate)
        new XmlSerializer(typeof(string[]))
            .Serialize(fs, types.Select(t => t.FullName).ToArray())
}

public static IEnumerable<Type> LoadTypes(string filename)
{
    using (var fs = File.Open(filename, FileMode.Open)
    {
        var typeNames = (string[])
        new XmlSerializer(typeof(string[]))
            .Deserialize(fs);

        return typeNames.Select(t => Type.Load(t));
    }
}

Note: When working with any Stream (or really any IDisposable) you have to either call the Dispose method or use the using statement (as I did above). This ensures that the IDisposable is properly cleaned up (ie releases File System handles).

Upvotes: 3

Related Questions