2008-09-17 26 views
87

Tôi đang tìm một cách dễ dàng để kiểm tra xem một đối tượng trong C# có thể tuần tự hóa không.Làm thế nào để kiểm tra xem một đối tượng có thể tuần tự hóa trong C#

Như chúng ta đã biết bạn thực hiện một đối tượng serializable bởi một trong hai thực hiện giao diện ISerializable hoặc bằng cách đặt [Serializable] ở phía trên cùng của lớp.

Điều tôi đang tìm kiếm là cách nhanh chóng để kiểm tra điều này mà không phải phản ánh lớp học để có được thuộc tính của nó. Giao diện sẽ nhanh chóng sử dụng câu hỏi là câu lệnh.

Sử dụng gợi ý @ Flard đây là mã mà tôi đã đưa ra, tiếng la hét là có cách tốt hơn.

private static bool IsSerializable(T obj) 
{ 
    return ((obj is ISerializable) || (Attribute.IsDefined(typeof (T), typeof (SerializableAttribute)))); 
} 

Hoặc thậm chí tốt hơn chỉ nhận được các loại của đối tượng và sau đó sử dụng tài sản IsSerializable vào loại:

typeof(T).IsSerializable 

Ghi mặc dù điều này điều này dường như chỉ mới lớp mà chúng ta đang đối phó với nếu lớp có chứa các lớp khác bạn có thể muốn kiểm tra tất cả hoặc thử và tuần tự hóa và đợi các lỗi như @pb chỉ ra.

+1

Xin lỗi thất bại khi một lĩnh vực trong obj không serializable, xem mẫu của tôi . –

+0

Tôi nghĩ đây là cách tiếp cận tốt hơn nhiều: http://stackoverflow.com/questions/236599/how-to-unit-test-if-my-object-is-really-serializable/236698#236698 – xero

+0

Tuyên bố "bạn làm cho một đối tượng có thể tuần tự hóa bằng cách thực hiện giao diện ISerializable hoặc bằng cách đặt [Serializable] ở đầu lớp "là sai. Đối với một đối tượng được serializable, lớp của nó phải khai báo SerializableAttribute. Việc triển khai ISerializable chỉ cho phép bạn kiểm soát nhiều hơn quy trình. – Mishax

Trả lời

99

Bạn có một tài sản đáng yêu trên lớp Type gọi IsSerializable.

+6

Điều này sẽ chỉ thông báo cho bạn nếu thuộc tính của Serializable được đính kèm vào lớp học của bạn. – Fatema

+2

@ Fatema: Quan điểm của bạn là gì? – leppie

+30

điểm của mình là các thành viên của đối tượng đó có thể không được tuần tự hóa mặc dù loại có chứa là. đúng? là nó không phải là trường hợp mà chúng ta phải đệ quy khoan vào các thành viên đối tượng và kiểm tra mỗi một, nếu không chỉ cố gắng serialize nó và xem nếu nó không thành công? –

6
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute)); 

Có lẽ liên quan đến phản chiếu dưới nước, nhưng cách đơn giản nhất?

+0

OOOH! Tuyệt vời ... – FryHard

40

Bạn sẽ phải kiểm tra tất cả các loại trong đồ thị của các đối tượng đang được tuần tự hóa cho thuộc tính có thể tuần tự hóa. Cách dễ nhất là thử serialize đối tượng và bắt ngoại lệ. (Nhưng đó không phải là giải pháp sạch nhất). Type.IsSerializable và việc kiểm tra thuộc tính serializalbe không tính đến đồ thị.

mẫu

[Serializable] 
public class A 
{ 
    public B B = new B(); 
} 

public class B 
{ 
    public string a = "b"; 
} 

[Serializable] 
public class C 
{ 
    public D D = new D(); 
} 

[Serializable] 
public class D 
{ 
    public string d = "D"; 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 

     var a = typeof(A); 

     var aa = new A(); 

     Console.WriteLine("A: {0}", a.IsSerializable); // true (WRONG!) 

     var c = typeof(C); 

     Console.WriteLine("C: {0}", c.IsSerializable); //true 

     var form = new BinaryFormatter(); 
     // throws 
     form.Serialize(new MemoryStream(), aa); 
    } 
} 
5

Dưới đây là một biến thể 3.5 làm cho nó có sẵn cho tất cả các lớp bằng cách sử dụng một phương pháp mở rộng.

public static bool IsSerializable(this object obj) 
{ 
    if (obj is ISerializable) 
     return true; 
    return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute)); 
} 
8

Sử dụng Type.IsSerializable như những người khác đã chỉ ra.

Có thể không đáng để phản ánh và kiểm tra xem tất cả các thành viên trong biểu đồ đối tượng có thể tuần tự hóa không.

Một thành viên có thể được khai báo là một loại serializable, nhưng trên thực tế được khởi tạo như một loại có nguồn gốc đó không phải là serializable, như trong ví dụ giả tạo như sau:

[Serializable] 
public class MyClass 
{ 
    public Exception TheException; // serializable 
} 

public class MyNonSerializableException : Exception 
{ 
... 
} 

... 
MyClass myClass = new MyClass(); 
myClass.TheException = new MyNonSerializableException(); 
// myClass now has a non-serializable member 

Vì vậy, ngay cả khi bạn xác định rằng một Ví dụ cụ thể của loại của bạn là serializable, bạn có thể không nói chung chắc chắn điều này sẽ là đúng của tất cả các trường hợp.

16

Đây là câu hỏi cũ, có thể cần được cập nhật cho .NET 3.5+. Type.IsSerializable thực sự có thể trả về false nếu class sử dụng thuộc tính DataContract.Dưới đây là một đoạn trích tôi sử dụng, nếu nó stinks, cho tôi biết :)

public static bool IsSerializable(this object obj) 
{ 
    Type t = obj.GetType(); 

    return Attribute.IsDefined(t, typeof(DataContractAttribute)) || t.IsSerializable || (obj is IXmlSerializable) 

} 
+0

Câu hỏi cũ và câu trả lời cũ nhưng điều này là rất đúng! Type.IsSerializable chỉ là một giải pháp một phần chức năng. Trong thực tế, cho bao nhiêu sử dụng WCF và DataContracts những ngày này, nó thực sự là một giải pháp rất nghèo! – Jaxidian

0

Đối tượng ngoại lệ có thể được serializable, nhưng sử dụng một ngoại lệ khác mà không phải là. Đây là những gì tôi đã có với WCF System.ServiceModel.FaultException: FaultException là serializable nhưng ExceptionDetail không phải là!

Vì vậy, tôi đang sử dụng như sau:

// Check if the exception is serializable and also the specific ones if generic 
var exceptionType = ex.GetType(); 
var allSerializable = exceptionType.IsSerializable; 
if (exceptionType.IsGenericType) 
    { 
     Type[] typeArguments = exceptionType.GetGenericArguments(); 
     allSerializable = typeArguments.Aggregate(allSerializable, (current, tParam) => current & tParam.IsSerializable); 
    } 
if (!allSerializable) 
    { 
     // Create a new Exception for not serializable exceptions! 
     ex = new Exception(ex.Message); 
    } 
1

tôi lấy câu trả lời về câu hỏi này và câu trả lời here và sửa đổi nó để bạn có được một danh sách các loại mà không phải là serializable. Bằng cách đó bạn có thể dễ dàng biết cái nào cần đánh dấu.

private static void NonSerializableTypesOfParentType(Type type, List<string> nonSerializableTypes) 
    { 
     // base case 
     if (type.IsValueType || type == typeof(string)) return; 

     if (!IsSerializable(type)) 
      nonSerializableTypes.Add(type.Name); 

     foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) 
     { 
      if (propertyInfo.PropertyType.IsGenericType) 
      { 
       foreach (var genericArgument in propertyInfo.PropertyType.GetGenericArguments()) 
       { 
        if (genericArgument == type) continue; // base case for circularly referenced properties 
        NonSerializableTypesOfParentType(genericArgument, nonSerializableTypes); 
       } 
      } 
      else if (propertyInfo.GetType() != type) // base case for circularly referenced properties 
       NonSerializableTypesOfParentType(propertyInfo.PropertyType, nonSerializableTypes); 
     } 
    } 

    private static bool IsSerializable(Type type) 
    { 
     return (Attribute.IsDefined(type, typeof(SerializableAttribute))); 
     //return ((type is ISerializable) || (Attribute.IsDefined(type, typeof(SerializableAttribute)))); 
    } 

Và sau đó bạn gọi nó là ...

List<string> nonSerializableTypes = new List<string>(); 
    NonSerializableTypesOfParentType(aType, nonSerializableTypes); 

Khi nó chạy, nonSerializableTypes sẽ có danh sách. Có thể có cách tốt hơn để thực hiện việc này hơn là chuyển vào một Danh sách trống sang phương thức đệ quy. Ai đó sửa tôi nếu vậy.

0

Giải pháp của tôi, trong VB.NET:

Đối tượng:

''' <summary> 
''' Determines whether an object can be serialized. 
''' </summary> 
''' <param name="Object">The object.</param> 
''' <returns><c>true</c> if object can be serialized; otherwise, <c>false</c>.</returns> 
Private Function IsObjectSerializable(ByVal [Object] As Object, 
             Optional ByVal SerializationFormat As SerializationFormat = 
                      SerializationFormat.Xml) As Boolean 

    Dim Serializer As Object 

    Using fs As New IO.MemoryStream 

     Select Case SerializationFormat 

      Case Data.SerializationFormat.Binary 
       Serializer = New Runtime.Serialization.Formatters.Binary.BinaryFormatter() 

      Case Data.SerializationFormat.Xml 
       Serializer = New Xml.Serialization.XmlSerializer([Object].GetType) 

      Case Else 
       Throw New ArgumentException("Invalid SerializationFormat", SerializationFormat) 

     End Select 

     Try 
      Serializer.Serialize(fs, [Object]) 
      Return True 

     Catch ex As InvalidOperationException 
      Return False 

     End Try 

    End Using ' fs As New MemoryStream 

End Function 

Đối với các loại:

''' <summary> 
''' Determines whether a Type can be serialized. 
''' </summary> 
''' <typeparam name="T"></typeparam> 
''' <returns><c>true</c> if Type can be serialized; otherwise, <c>false</c>.</returns> 
Private Function IsTypeSerializable(Of T)() As Boolean 

    Return Attribute.IsDefined(GetType(T), GetType(SerializableAttribute)) 

End Function 

''' <summary> 
''' Determines whether a Type can be serialized. 
''' </summary> 
''' <typeparam name="T"></typeparam> 
''' <param name="Type">The Type.</param> 
''' <returns><c>true</c> if Type can be serialized; otherwise, <c>false</c>.</returns> 
Private Function IsTypeSerializable(Of T)(ByVal Type As T) As Boolean 

    Return Attribute.IsDefined(GetType(T), GetType(SerializableAttribute)) 

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