很多时候,我们需要将对象序列化成字符串保存到内存、磁盘或者 Page.ViewState 中。基于种种原因,我们希望序列化结果尽可能小,尽可能简单,即便用其他的方法(比如正则表达式)也能解析出数据。BinaryFormatter 的结果转换成字符串(或者Base64)长度太大,而 XmlSerializer 对数据类型支持有限,显然内置的序列化引擎不足以满足我们的需求,还是自己丰衣足食。


下面的代码可能还不完善,仅供参考,内容比较简单,不做详述。

/// <summary>

/// 序列化

/// </summary>

public static string SerializeObject(object o)

{

  char sep1 = '|';

  char sep2 = ',';

  char sep3 = '=';


  StringBuilder sb = new StringBuilder();


  FieldInfo[] fields = o.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public |

    BindingFlags.NonPublic);


  foreach (FieldInfo field in fields)

  {

    object value = field.GetValue(o);


    if (value != null)

    {

      if (field.FieldType.GetInterface("IDictionary") != null)

      {

        foreach (object key in (value as IDictionary).Keys)

        {

          sb.AppendFormat("{0}{3}{1}{2}", key, (value as IDictionary)[key], sep2, sep3);

        }


        if (sb[sb.Length - 1] == sep2) sb.Remove(sb.Length - 1, 1);

      }

      else if (field.FieldType.GetInterface("IList") != null)

      {

        foreach (object v in (value as IList))

        {

          sb.AppendFormat("{0}{1}", v, sep2);

        }


        if (sb[sb.Length - 1] == sep2) sb.Remove(sb.Length - 1, 1);

      }

      else if (field.FieldType == typeof(Boolean))

      {

        sb.Append((bool)value ? "T" : "");

      }

      else

      {

        sb.Append(value);

      }

    }


    sb.Append(sep1);

  }


  if (sb[sb.Length - 1] == sep1) sb.Remove(sb.Length - 1, 1);

  return sb.ToString();

}


/// <summary>

/// 反序列化

/// </summary>

public static T DeserializeObject<T>(string s)

  where T : new()

{

  char sep1 = '|';

  char sep2 = ',';

  char sep3 = '=';


  T o = new T();


  FieldInfo[] fields = o.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public |

    BindingFlags.NonPublic);


  string[] values = s.Split(sep1);


  for (int i = 0; i < fields.Length; i++)

  {

    FieldInfo field = fields[i];

    if (String.IsNullOrEmpty(values[i])) continue;


    if (field.FieldType.GetInterface("IDictionary") != null)

    {

      string[] vs = values[i].Split(sep2);


      IDictionary dictionary = field.GetValue(o) as IDictionary;


      Type key = field.FieldType.IsGenericType ?

        field.FieldType.GetGenericArguments()[0] : typeof(Object);

      Type value = field.FieldType.IsGenericType ?

        field.FieldType.GetGenericArguments()[1] : typeof(Object);


      if (dictionary == null)

      {

        dictionary = (IDictionary)Activator.CreateInstance(field.FieldType);

        field.SetValue(o, dictionary);

      }


      foreach (string v in vs)

      {

        string[] ns = v.Split(sep3);

        dictionary.Add(Convert.ChangeType(ns[0], key), Convert.ChangeType(ns[1], value));

      }

    }

    else if (field.FieldType.GetInterface("IList") != null)

    {

      string[] vs = values[i].Split(sep2);


      if (field.FieldType.IsArray)

      {

        Type t = field.FieldType.GetElementType();

        Array array = Array.CreateInstance(t, vs.Length);


        for (int x = 0; x < vs.Length; x++)

        {

          array.SetValue(Convert.ChangeType(vs[x], t), x);

        }


        field.SetValue(o, array);

      }

      else

      {

        IList list = field.GetValue(o) as IList;


        Type t = field.FieldType.IsGenericType ?

          field.FieldType.GetGenericArguments()[0] : typeof(Object);


        if (list == null)

        {

          list = (IList)Activator.CreateInstance(field.FieldType);

          field.SetValue(o, list);

        }


        foreach (string v in vs)

        {

          list.Add(Convert.ChangeType(v, t));

        }

      }

    }

    else if (field.FieldType == typeof(Boolean))

    {

      field.SetValue(o, values[i] == "T" ? true : false);

    }

    else if (field.FieldType.IsEnum)

    {

      field.SetValue(o, Enum.Parse(field.FieldType, values[i], true));

    }

    else

    {

      field.SetValue(o, Convert.ChangeType(values[i], field.FieldType));

    }

  }


  return o;

}


测试代码

[Serializable]

public class MyClass

{

  private int valueType;


  public int ValueType

  {

    get { return valueType; }

    set { valueType = value; }

  }


  private object obj;


  public object Object

  {

    get { return obj; }

    set { obj = value; }

  }


  private bool boolean;


  public bool Boolean

  {

    get { return boolean; }

    set { boolean = value; }

  }


  private string[] array;


  public string[] Array

  {

    get { return array; }

    set { array = value; }

  }


  private List<string> list;


  public List<string> List

  {

    get { return list; }

    set { list = value; }

  }


  private ArrayList arrayList;


  public ArrayList ArrayList

  {

    get { return arrayList; }

    set { arrayList = value; }

  }


  private Hashtable hashtable;


  public Hashtable Hashtable

  {

    get { return hashtable; }

    set { hashtable = value; }

  }


  private Dictionary<string, int> dictionary;


  public Dictionary<string, int> Dictionary

  {

    get { return dictionary; }

    set { dictionary = value; }

  }

}


class Program

{

  static void Main(string[] args)

  {

    //Test();


    MyClass o = new MyClass();

    o.List = new List<string>();

    o.Dictionary = new Dictionary<string, int>();

    o.ArrayList = new ArrayList();

    o.Hashtable = new Hashtable();


    o.ValueType = 123456;

    o.Object = DateTime.Now;

    o.Boolean = true;


    o.Dictionary.Add("dict1", 1);

    o.Dictionary.Add("dict2", 2);

    

    o.Array = new string[] { "array1", "array2", "array3" };

    

    o.List.Add("list1");

    o.List.Add("list2");

    

    o.ArrayList.Add("ArrayList1");

    o.ArrayList.Add("ArrayList2");

    

    o.Hashtable.Add("Hashtable1", 1);

    o.Hashtable.Add("Hashtable2", 2);


    // SerializeObject


    string s = SerializeObject(o);

    Console.WriteLine(s);


    MyClass m = DeserializeObject<MyClass>(s);

    Console.WriteLine(SerializeObject(m));


    // BinaryFormatter


    BinaryFormatter binary = new BinaryFormatter();

    MemoryStream stream = new MemoryStream();

    binary.Serialize(stream, o);

    s = Convert.ToBase64String(stream.ToArray());

    Console.WriteLine(s);

  }

}