views:

442

answers:

2

I'm writing a custom deserializer that will deserialize a list by deserializing each of the individual objects in the collection and then putting it together.

Basically my code looks like this:

//myField is a FieldInfo that represents the field we want to put the data in
//resultObject is the object we want the data to go into

List<Object> new_objects = new List<Object>();
foreach (String file_name in file_name_list)
{
     Object field_object = MyDeserialization(file_name)
     new_objects.Add(field_object)
}
myField.SetValue(resultObject, new_objects);

But this gives an error on the SetValue because (for example) I am trying to put a List(Object) into a List(Int32). Note that this problem only occurs with collections. The following code:

Object new_object = MyDeserialization(file_name)
myField.SetValue(resultObject, new_object)

works just fine provided that the runtime type of the result of MyDeserialization(file_name) is actually compatible with the type of myField. What is the problem here, and is there a way to make the collection deserialization work? (I've tried replacing the List(Object) declaration with myField.FieldType and that won't even compile.

A: 

The problem is that .NET can't know that your List is actually a List. The following code should work:

//myField is a FieldInfo that represents the field we want to put the data in
//resultObject is the object we want the data to go into

List<MyType> new_objects = new List<MyType>();
foreach (String file_name in file_name_list)
{
     Object field_object = MyDeserialization(file_name)
     new_objects.Add((MyType)field_object)
}
myField.SetValue(resultObject, new_objects);

For Fun Linq Extra Credit (assuming file_name_list is IEnumerable):

myField.SetValue(resultObject, file_name_list
           .Select(s => MyDeserialization(s))
           .Cast<MyType>()
           .ToList());
Talljoe
This wouldn't work because MyType is unknown at compile time.
Alex319
A: 

Collections do not offer covariance... a List<int> simply isn't a List<object> (or v.v.). As such, you need to identify the T, for example like so (using the FieldInfo.FieldType) - and create the right type of list in the first place.

For convenience, once created it may be simpler to use the non-generic IList interface:

Type listType = typeof(List<>).MakeGenericType(itemType);
IList list = (IList)Activator.CreateInstance(listType);
list.Add(...); // etc

However; I must stress - writing a full (and robust) serializer is a lot of work. Do you have a specific reason? Many of the inbuilt serializers are pretty good - for example DataContractSerializer - or 3rd party, such as Json.Net, and (if I do say so myself) protobuf-net.

Marc Gravell
Actually, I'm not really writing an entire custom serializer. What I'm trying to do is take a very large object and break it up into a whole bunch of smaller objects that can be serialized each in a separate file. For example if one of the fields in the object was a list of 50 records, and each record was a megabyte, if I want to pull out one record I would want to have a way of just deserializing the one record that I want, rather than deserializing the whole object with all 50 records. My serializer would then call a built in serializer to serialize the broken up objects.
Alex319