Serializing Data Transfer Objects in .NET

佐手、 提交于 2019-12-01 17:00:16

The best approach would be something like this, this is my favourite approach:

public class SomeClass : ISerializable{
   private float _fVersion;
   ....
   public float Version {
       get { return this._fVersion; }
   }

   private SomeClass(SerializationInfo info, StreamingContext context) {
      bool bOk = false;
      this._fVersion = info.GetSingle("versionID");
      if (this._fVersion == 1.0F) bOk = this.HandleVersionOnePtZero(info, context);
      if (this._fVersion == 1.1F) bOk = this.HandleVersionOnePtOne(info, context);

      if (!bOk) throw new SerializationException(string.Format("SomeClass: Could not handle this version {0}.", this._fVersion.ToString()));
   }
   public void GetObjectData(SerializationInfo info, StreamingContext context) {
      info.AddValue("versionID", this._fVersion);
      if (this._fVersion == 1.0F) {
         info.AddValue("someField", ...);
         info.AddValue("anotherField", ...);
      }
      if (this._fVersion == 1.1F) {
         info.AddValue("someField1", ...);
         info.AddValue("anotherField2", ...);
      }
   }
   private bool HandleVersionOnePtZero(SerializationInfo info, StreamingContext context) {
      bool rvOk = false;
      ... = info.GetValue("someField");
      ... = info.GetValue("anotherField");
   }

   private bool HandleVersionOnePtOne(SerializationInfo info, StreamingContext context) {
      bool rvOk = false;
      ... = info.GetValue("someField1");
      ... = info.GetValue("anotherField2");
   }

}

This is how I enforce a tighter grain of control over the serialization of binary data and bump up the version. Now, those of you will point out that there is already a feature available to do this, but coming from .NET 1.1, well, old habits die hard.

Notice how in the code sample above I used two different methods HandleVersionOnePtZero and HandleVersionOnePtOne to handle the different versions of the serialized stream. By doing it this way, I have a greater degree of flexibility, say what if the field someField needs to be changed? Also, notice how the _fVersion field is the first thing the serializable routine does firstly, then checks the version of the field and decide which one to use.

The only thing about this, is if you change the namespace, then you will have difficulty deserializing the data, but you can use the SerializationBinder class as an example:

public class SomeClassBinder : System.Runtime.Serialization.SerializationBinder {
    public override Type BindToType(string assemblyName, string typeName) {
      Type typeToDeserialize = null;
      try {
         // For each assemblyName/typeName that you want to deserialize to
         // a different type, set typeToDeserialize to the desired type.
         string assemVer1 = System.Reflection.Assembly.GetExecutingAssembly().FullName;
         if (assemblyName.StartsWith("foobar")) {
             assemblyName = assemVer1;
             typeName = "fubar" + typeName.Substring(typeName.LastIndexOf("."), (typeName.Length - typeName.LastIndexOf(".")));
         }
         typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
      } catch (System.Exception ex1) {
          throw ex1;
      } finally {
    }
    return typeToDeserialize;
  }
}

it would be called like this:
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new SomeClassBinder();
SomeClass sc = bf.Deserialize(stream); // assume stream is declared and open

Hope this helps

There are already some built in mechanisms for doing xml serialization in .NET.

Attribute based serialization - overview. All you have to do is tag your class's members with attributes and use the XmlSerializer class to serialize / deserialize the type.


    [XmlRoot("myXmlClass")]
    public class MyXmlClass
    {
        [XmlAttribute("myAttribtue")]
        public string MyAttribute { get; set; }
        [XmlElement("myElement")]
        public string MyElement { get; set; }
    }

    var output = new MemoryStream();
    var serializer = new XmlSerializer(typeof(MyXmlClass));
    serializer.Serialize(output, new MyXmlClass { MyAttribute = "foo", MyElement = "bar" });

Output -

<myXmlClass myAttribute="foo">
    <myElement>bar</myElement>
</myXmlClass>

Or you can make all of your xml serializable classes implement IXmlSerializable.

Edit - Now since I misunderstood your original question I'll amend this with a technique you could use to serialize the same object into multiple different xml formats.

Now that your data transfer object is serializable into at least one xml based format you could do a post translation step to get it into the format you want using xslt transforms. Xslt is a way to take xml and translate it into anything using an xslt file for instructions. In this case you would be translating into another xml format.

Here's how (assuming you've already written your xslt file) -


    // output stream from before
    output.Seek(0, SeekOrigin.Begin);
    var reader = XmlReader.Create(output);
    // cache this for performance reasons
    XslCompiledTransform transform = new XslCompiledTransform();
    transform.Load("c:\myTransforms\commonToFormatA.xslt");
    var writer = XmlWriter.Create(Console.Out); // write final output to console.
    transform.Transform(reader, writer);

Part of the consideration will be how different the XML formats are. In particular, can they all be accomplished by using the overrides feature of XML Serialization? That allows you to provide an array of entries overriding features like element or attribute name / whether to serialize as elements or attributes, etc.

This could permit you to have your various formats differ only in terms of the override array passed to the serialization process. That would leave you with the question of how to determine the array to pass.

Read up about Custom XML Serializers, they should be able to do everything that you require.

http://geekswithblogs.net/marcel/archive/2006/05/19/78989.aspx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!