Jak sprawdzić, czy obiekt jest serializowalny w C#

Szukam łatwego sposobu, aby sprawdzić, czy obiekt w C# jest serializowalny.

Jak wiemy tworzysz obiekt serializowalny poprzez implementację interfejsu ISerializable lub poprzez umieszczenie [Serializowalny] na górze klasy.

Szukam szybkiego sposobu, aby to sprawdzić bez konieczności odzwierciedlania klasy, aby uzyskać jej atrybuty. Interfejs byłby szybki przy użyciu instrukcji is.

Using @ Flard ' s sugestia to jest kod, który wymyśliłem, Krzyk jest lepszy sposób.

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

Lub jeszcze lepiej po prostu pobierz typ obiektu, a następnie użyj właściwości IsSerializable na typie:

typeof(T).IsSerializable

Pamiętaj jednak, że wydaje się to tylko klasą, z którą mamy do czynienia, jeśli klasa zawiera inne klasy, prawdopodobnie chcesz sprawdzić je wszystkie lub spróbować serializować i czekać na błędy, jak zauważył @pb.

Author: FryHard, 2008-09-17

9 answers

Masz śliczną nieruchomość na Type klasie o nazwie IsSerializable.

 116
Author: leppie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-07 07:31:11

Będziesz musiał sprawdzić wszystkie typy na wykresie obiektów serializowanych dla atrybutu serializowalnego. Najprostszym sposobem jest próba serializacji obiektu i złapania wyjątku. (Ale to nie jest najczystsze rozwiązanie). Typ.ISerializable i sprawdzanie atrybutu serializalbe nie bierze pod uwagę wykresu.

próbka

[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);
    }
}
 43
Author: Paul van Brenk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 10:25:57

To jest stare pytanie, które może wymagać aktualizacji dla. NET 3.5+. Typ.IsSerializable może zwracać false, jeśli Klasa używa atrybutu DataContract. Oto fragment, którego używam, jeśli śmierdzi, daj znać:)

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

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

}
 18
Author: Mike_G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-27 21:22:32

Użyj Typu.ISerializable, jak wskazywali inni.

Prawdopodobnie nie warto próbować odzwierciedlać i sprawdzać, czy wszystkie elementy w grafie obiektu są serializowalne.

Element może być zadeklarowany jako typ serializowalny, ale w rzeczywistości może być utworzony jako typ Pochodny, który nie jest serializowalny, jak w poniższym przykładzie:

[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

Dlatego, nawet jeśli ustalisz, że konkretna instancja Twojego typu jest serializowalna, nie możesz być pewien, że to spowoduje być prawdziwe we wszystkich przypadkach.

 9
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 11:46:14
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

Prawdopodobnie wiąże się z odbiciem pod wodą, ale najprostszy sposób?

 6
Author: Grad van Horck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 10:12:21

Oto odmiana 3.5, która udostępnia ją wszystkim klasom za pomocą metody rozszerzenia.

public static bool IsSerializable(this object obj)
{
    if (obj is ISerializable)
        return true;
    return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute));
}
 5
Author: Michael Meadows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 10:29:15

Wziąłem odpowiedź na to pytanie i odpowiedź TUTAJ i zmodyfikowałem ją tak, aby uzyskać listę typów, które nie są serializowane. W ten sposób możesz łatwo wiedzieć, które z nich zaznaczyć.

    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))));
    }
/ Align = "left" / ..
    List<string> nonSerializableTypes = new List<string>();
    NonSerializableTypesOfParentType(aType, nonSerializableTypes);

Po uruchomieniu, nonserializabletypy będą miały listę. Może być na to lepszy sposób niż przekazanie pustej listy do metody rekurencyjnej. Ktoś mnie poprawi, jeśli tak.

 2
Author: sewershingle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:50

Moje rozwiązanie, w VB.NET:

Dla Obiektów:

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

Dla Typów:

''' <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
 1
Author: ElektroStudios,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-02 15:33:26

Obiekt exception może być serializowalny , ale używa innego wyjątku, który nie jest. To właśnie miałem z systemem WCF.ServiceModel.FaultException: FaultException jest serializowalny, ale ExceptionDetail nie jest!

Więc używam:

// 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
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-06 14:43:20