次の方法で共有


Generic DataContract Serializer or The Last DataContract Serializer on Earth

Alternate post title is written with apologies to  Vicent Price.

 When working with any technology that requires a contract driven approach, like WCF, there is often a need to serialize and deserialize objects if they don't come from a well know source exposing a complex type. You may find yourself in the position of having to read from disk or write an object to disk. Development of a front end may need to be created in parallel with the service that will supply it with populated data contracts. Until that service is available stubbed XML files may be user to populate predefined data contracts until the service becomes available. Code similar to the following is required:

public MyDataContract ReadObject(string objectData)
{
  MyDataContract deserializedObject = default(T);
  using (StringReader reader = new StringReader(objectData))
  {
     XmlTextReader xmlReader = new XmlTextReader(reader);
     XmlSerializer ser = new XmlSerializer(typeof(MyDataContract));
     deserializedObject = (MyDataContract)ser.ReadObject(xmlReader, true);
     xmlReader.Close();
  }
  return deserializedObject;
}

With each schema that's stubbed out and deserialized a new ReadObject method is required. A more generic approach obviates this tendency:

using System.Xml;
using System.IO;
using System.Runtime.Serialization;

namespace MyCompany.Serialization
{
  internal static class GenericDataContractSerializer<T>
  {
     public static void WriteObject(T outputObject, string outputFile)
     {
        using (FileStream writer = new FileStream(outputFile, FileMode.Create))
        {
           DataContractSerializer ser = new DataContractSerializer(typeof(T));
           ser.WriteObject(writer, outputObject);
        }
     }

public static T ReadObject(string objectData)
     {
        T deserializedObject = default(T);
        using (StringReader reader = new StringReader(objectData))
        {
           XmlTextReader xmlReader = new XmlTextReader(reader);
           DataContractSerializer ser = new DataContractSerializer(typeof(T));
           deserializedObject = (T)ser.ReadObject(xmlReader, true);
           xmlReader.Close();
        }
        return deserializedObject;
     }
  }
}

The class is used as follows:

string locationText = GetFile("MyStubbedDataContract.xml");
returnValue = GenericDataContractSerializer<MyDataContract>.ReadObject(locationText);

GetFile is responsible to loading the stubbed file which could come from the file system or from the resources of the assembly. For what it's worth I prefer to keep the stubbed files as an embedded resource since it removes the need to move yet another file during deployment to a development server. By the time it goes to production the stubbed approach should have been abandoned in favor of a working service that returns data contracts dynamically populated with data.

If you're dealing with XML serialization, here's the analog class for a generic XML Serializer:

using System.Xml;
using System.IO;
using System.Xml.Serialization;

namespace MyCompany.Serialization
{
  internal static class GenericXmlSerializer<T>
  {
    public static void WriteObject(T outputObject, string outputFile)
    {
      using (FileStream writer = new FileStream(outputFile, FileMode.Create))
      {
        XmlSerializer ser = new XmlSerializer(typeof(T));
        ser.Serialize(writer, outputObject);
      }
    }

    public static T ReadObject(string objectData)
    {
      T deserializedObject = default(T);
     
      using (StringReader reader = new StringReader(objectData))
      {
        XmlTextReader xmlReader = new XmlTextReader(reader);
        XmlSerializer ser = new XmlSerializer(typeof(T));
        deserializedObject = (T)ser.Deserialize(xmlReader);
        xmlReader.Close();
      }

return deserializedObject;
    }
  }
}