it-swarm-vi.com

Cách kiểm tra xem một đối tượng có được tuần tự hóa trong C # không

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

Như chúng ta biết, bạn tạo một đối tượng tuần tự hóa bằng cách triển khai giao diện ISerializable hoặc bằng cách đặt [Nối tiếp] ở đầu lớp.

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

Sử dụng đề xuất của @ Flard đây là mã mà tôi đã nghĩ ra, hét lên là có một 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ỉ cần lấy loại đối tượng và sau đó sử dụng thuộc tính IsSerializable trên loại:

typeof(T).IsSerializable

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

92
FryHard

Bạn có một thuộc tính đáng yêu trên lớp Type được gọi là IsSerializable.

113
leppie

Bạn sẽ phải kiểm tra tất cả các loại trong biểu đồ của các đối tượng được tuần tự hóa cho thuộc tính tuần tự hóa. Cách dễ nhất là cố gắng tuần tự hóa đố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à kiểm tra thuộc tính serializalbe không đưa biểu đồ vào tài khoản.

Mẫ

[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);
    }
}
41
Paul van Brenk

Đây là một 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 lớp sử dụng thuộc tính DataContract. Đây là một đoạn tôi sử dụng, nếu nó bốc mùi, hãy 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)

}
16
Mike_G

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

Có lẽ không đáng để cố gắ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ó được tuần tự hóa hay không.

Một thành viên có thể được khai báo là một kiểu tuần tự hóa, nhưng trên thực tế được khởi tạo như một kiểu dẫn xuất không thể tuần tự hóa, như trong ví dụ giả đị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

Do đó, ngay cả khi bạn xác định rằng một phiên bản cụ thể của loại của bạn là tuần tự hóa, nói chung bạn không thể chắc chắn điều này sẽ đúng với tất cả các trường hợp.

8
Joe
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

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

6
Grad van Horck

Đâ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 phương thức mở rộng.

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

Tôi đã lấy câu trả lời cho câu hỏi này và câu trả lời tại đây và sửa đổi nó để bạn có được Danh sách các loại không tuần tự hóa. Bằng cách đó bạn có thể dễ dàng biết những gì để đá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ó ...

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

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

2
Andy Merrick

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

Đối với đố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
0
ElektroStudios

Đối tượng ngoại lệ có thể được tuần tự hóa, nhưng sử dụng một ngoại lệ khác thì không. Đây là những gì tôi vừa có với WCF System.ServiceModel.FaultException: FaultException có thể tuần tự hóa nhưng ExceptionDetail thì không!

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);
    }
0
Eric