it-swarm-id.com

Cara memeriksa apakah suatu objek dapat serial dalam C #

Saya mencari cara mudah untuk memeriksa apakah suatu objek dalam C # adalah serializable.

Seperti yang kita ketahui, Anda membuat objek serial dengan baik dengan mengimplementasikan antarmuka ISerializable atau dengan menempatkan [Serializable] di bagian atas kelas.

Apa yang saya cari adalah cara cepat untuk memeriksa ini tanpa harus mencerminkan kelas untuk mendapatkan atributnya. Antarmuka akan cepat menggunakan pernyataan is.

Menggunakan saran @ Flard, ini adalah kode yang saya buat, teriak ada cara yang lebih baik.

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

Atau bahkan lebih baik hanya mendapatkan jenis objek dan kemudian menggunakan properti IsSerializable pada tipe:

typeof(T).IsSerializable

Ingat meskipun ini sepertinya hanya kelas yang kita hadapi jika kelas berisi kelas-kelas lain, Anda mungkin ingin memeriksa semuanya atau mencoba dan membuat serial dan menunggu kesalahan seperti yang ditunjukkan oleh @pb.

92
FryHard

Anda memiliki properti yang bagus di kelas Type yang disebut IsSerializable.

113
leppie

Anda harus memeriksa semua jenis dalam grafik objek yang diserialisasi untuk atribut serializable. Cara termudah adalah mencoba membuat cerita bersambung objek dan menangkap pengecualian. (Tapi itu bukan solusi terbersih). Type.IsSerializable dan memeriksa atribut serializalbe tidak memperhitungkan grafik.

Sampel

[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

Ini adalah pertanyaan lama, yang mungkin perlu diperbarui untuk .NET 3.5+. Type.IsSerializable sebenarnya dapat mengembalikan false jika kelas menggunakan atribut DataContract. Ini adalah cuplikan yang saya gunakan, jika bau, beri tahu saya :)

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

Gunakan Type.Iserializable seperti yang orang lain tunjukkan.

Mungkin tidak layak untuk mencoba untuk merefleksikan dan memeriksa apakah semua anggota dalam objek grafik serializable.

Seorang anggota dapat dideklarasikan sebagai tipe serializable, tetapi pada kenyataannya akan dipakai sebagai tipe turunan yang tidak serializable, seperti dalam contoh dibuat berikut ini:

[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

Oleh karena itu, bahkan jika Anda menentukan bahwa contoh spesifik dari jenis Anda serializable, Anda secara umum tidak dapat memastikan ini akan berlaku untuk semua contoh.

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

Mungkin melibatkan refleksi di bawah air, tetapi cara paling sederhana?

6
Grad van Horck

Berikut adalah variasi 3.5 yang membuatnya tersedia untuk semua kelas menggunakan metode ekstensi.

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

Saya mengambil jawaban atas pertanyaan ini dan jawabannya di sini dan memodifikasinya sehingga Anda mendapatkan Daftar jenis yang tidak berseri. Dengan begitu Anda bisa dengan mudah tahu mana yang harus ditandai.

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

Dan kemudian Anda menyebutnya ...

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

Saat dijalankan, NonSerializableTypes akan memiliki daftar. Mungkin ada cara yang lebih baik untuk melakukan ini daripada menyerahkan Daftar kosong ke metode rekursif. Seseorang mengoreksi saya jika demikian.

2
Andy Merrick

Solusi saya, di VB.NET:

Untuk Objek:

''' <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

Untuk Jenis:

''' <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

Objek pengecualian mungkin serial, tetapi menggunakan pengecualian lain yang tidak. Inilah yang baru saja saya miliki dengan WCF System.ServiceModel.FaultException: FaultException adalah serializable tetapi ExceptionDetail tidak!

Jadi saya menggunakan yang berikut ini:

// 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