2012-12-19 18 views
43

Thông thường, tôi cần serialize một đối tượng, hoặc là để ghi nhật ký hoặc gỡ lỗi. Đây là một serialization một chiều - Tôi không cần phải làm cho nó trở lại sau này, tôi chỉ cần biến một đối tượng thành một chuỗi để viết nó ở đâu đó.Trong C#, làm thế nào để bạn một chiều serialize unserializable?

Có, có - đây là lý do tại sao bạn nên luôn ghi đè phương pháp ToString. Tôi biết cái này. Nhưng tôi thường đối phó với các đồ vật mà tôi không viết và không thể thay đổi. Ngoài ra, tôi không muốn phải viết và cập nhật một phương thức ToString cho mọi lớp tôi viết.

Tuần tự hóa XML cung cấp giải pháp dường như hoàn hảo - chỉ cần làm phẳng đối tượng đó ra thành XML. Nhưng có rất nhiều hạn chế, đặc biệt là bạn không thể serialize IDictionary, và bạn phải có một constructor parameterless. Tôi có thể học những thứ này trong lớp học của mình, nhưng - một lần nữa - tôi thường làm việc với các lớp của người khác.

Vì vậy, giải pháp để nhận được biểu diễn chuỗi toàn diện của một đối tượng là gì? Có cái gì đơn giản mà tôi đang thiếu?

+3

Có thể một số phản ánh để lặp lại và hiển thị các thành viên thành một chuỗi? Tuy nhiên, đó là chậm và do đó chỉ hợp lý cho các tình huống lỗi mà hiệu suất không quan trọng (nữa) ... –

Trả lời

38

Làm thế nào về một phương pháp mở rộng với logic của riêng bạn (và có thể một số Phản ánh)?

public static class SerializerExtension 
{ 
    public static String OneWaySerialize(this Object obj) 
    { 
     if (Object.ReferenceEquals(obj, null)) 
     { 
      return "NULL"; 
     } 
     if (obj.GetType().IsPrimitive || obj.GetType() == typeof(String)) 
     { 
      if (obj is String) 
       return String.Format("\"{0}\"", obj); 
      if (obj is Char) 
       return String.Format("'{0}'", obj); 
      return obj.ToString(); 
     } 

     StringBuilder builder = new StringBuilder(); 
     Type objType = obj.GetType(); 
     if (IsEnumerableType(objType)) 
     { 
      builder.Append("["); 

      IEnumerator enumerator = ((IEnumerable)obj).GetEnumerator(); 
      Boolean moreElements = enumerator.MoveNext(); 
      while (moreElements) 
      { 
       builder.Append(enumerator.Current.OneWaySerialize()); 
       moreElements = enumerator.MoveNext(); 
       if (moreElements) 
       { 
        builder.Append(","); 
       } 
      } 

      builder.Append("]"); 
     } 
     else 
     { 
      builder.AppendFormat("{0} {{ ", IsAnonymousType(objType) ? "new" : objType.Name); 

      PropertyInfo[] properties = objType.GetProperties(); 
      for (Int32 p = properties.Length; p > 0; p--) 
      { 
       PropertyInfo prop = properties[p-1]; 
       String propName = prop.Name; 
       Object propValue = prop.GetValue(obj, null); 
       builder.AppendFormat("{0} = {1}", propName, propValue.OneWaySerialize()); 
       if (p > 1) 
       { 
        builder.Append(", "); 
       } 
      } 

      builder.Append(" }"); 
     } 

     return builder.ToString(); 
    } 

    // http://stackoverflow.com/a/2483054/298053 
    private static Boolean IsAnonymousType(Type type) 
    { 
     if (type == null) 
     { 
      return false; 
     } 
     return Attribute.IsDefined(type, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false) 
      && type.IsGenericType && type.Name.Contains("AnonymousType") 
      && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) 
      && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; 
    } 

    private static Boolean IsEnumerableType(Type type) 
    { 
     if (type == null) 
     { 
      return false; 
     } 
     foreach (Type intType in type.GetInterfaces()) 
     { 
      if (intType.GetInterface("IEnumerable") != null || (intType.IsGenericType && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>))) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 
} 

Gọi nó như vậy:

someDefinedObject.OneWaySerialize(); 

Revisisons

  1. phiên bản ban đầu
  2. Cập nhật 12.26.2012
    • gia tăng kiểm tra cho IEnumerable (nhờ aboveyou00)
    • gia tăng kiểm tra cho loại vô danh (và chỉ gọi nó là "mới" khi đầu ra)
+0

+1: Phương pháp mở rộng và phản chiếu sẽ là mục yêu thích của tôi ở đây, đảm bảo tuần tự hóa các thuộc tính công khai. Có thể là một chút boggy cho các lớp học lớn mặc dù. –

+1

Rõ ràng không phải cho hiệu suất nhạy cảm, nhưng nó có vẻ giống như một công cụ gỡ lỗi hơn là một sản xuất để phản ánh nên _satisfactory_. –

+0

Tuyệt đối, chỉ cần đặt nó ra khỏi đó trong trường hợp OP quyết định đặt nó vào một cơ chế khai thác gỗ cho các đối tượng lớn trong một môi trường sử dụng nặng. Với OP không muốn viết một cho "mọi đối tượng" tôi đoán anh ấy định sử dụng "rất nhiều". –

14

Nếu bạn serializing thoải mái để JSON, Json.NET là một giải pháp tuyệt vời cho vấn đề này.

Các vấn đề liên quan