views:

631

answers:

3

I have a pretty sizeable object graph that I have serialized to a file via the DataContractSerializer. I now want to present a list of these files to the user to choose from. In this list, I want to show some of the details about the file, which are properties of the root object. I don't want to load the whole graph into memory, since I'm only interested in displaying properties of the root node.

Does anyone know a way to control the "depth" of the deserialization so that I can just pull the root object from the file and skip over the children? I'd rather avoid treating the file as raw XML, since I'm not doing any raw XML manipulations anywhere else, and that would be one more branch of code that I have to keep in sync.

My only idea right now is to create a compatible "summary" object containing only the properties I'm interested in, and none of the children, and deserialize the file into that. This should skip the children since they are not relevant to the summary object.

Is there a better way to accomplish this?

Update/Clarification: Attributes are not the answer I'm looking for. For one thing, they'll prevent the "extra" properties from ending up in the file when the object was first serialized.

Second, they're more permanent than what I'm trying to do. Eventually, I do want to deserialize the entire file, just not at this point. I'm trying to show a summary list of files that the user will choose from for import. During the import, I'm going to need all the children and grandchildren. It's just overkill during step 1. These are potentially large files, so fully deserializing several of them just so I can display their header information isn't going to work.

Hopefully that clears up any confusion about the original question.

A: 

you can control your serialization by using attributes. read more here

Schwartser
+1  A: 

That's pretty much the way you want to do it. The DataContractSerializer is meant to handle this situation, where you have to types that are conceptually the same, but different types from the CLR's point of view which you want to serialize into each other.

Given that, just create the object with the similar subset of properties that you want to serialize and pass that type to the DataContractSerializer.

Make sure that on the "summary" type that you set the properties of the DataContract attribute (as well as any DataMember attributes or DataContract attributes on children you expose), specifically the Name and Namespace properties to reflect the name and namespace of the non-summary type (since these must match).

casperOne
+1  A: 

My first recommendation would be to do the XML manipulation if you just want to pull out some details from the root node. Another possibility, though I don't know the performace implications, is to use the versioning capabilities of DataContractSerializer for this problem. On your data contract, mark every field except the ones you will need in the summary as Optional. Then, copy the data contract as another class, leaving out the optional fields. Deserialize to the new, smaller data contract.

class Program
{
    static void Main(string[] args)
    {
        Person a = new Person();
        Person b = new Person();
        a.Name = "Mike";
        b.Name = "Joe";
        b.Parent = a;

        DataContractSerializer dtc = new DataContractSerializer(typeof(Person));

        StringBuilder sb = new StringBuilder();
        using (XmlWriter xr = XmlWriter.Create(sb))
        {
            dtc.WriteObject(xr, b);
        }

        object n;

        DataContractSerializer dtc2 = new DataContractSerializer(typeof(TinyPerson));

        using (XmlReader xr = XmlReader.Create(new StringReader(sb.ToString())))
        {
            n = dtc2.ReadObject(xr);
        }

    }
}

[DataContract(Name="Person")]
public class Person
{
    [DataMember]
    public string Name;

    [DataMember(IsRequired=false)]
    public Person Parent; 
}


[DataContract(Name = "Person")]
public class TinyPerson
{
    [DataMember]
    public string Name;

}
foson