it-swarm-eu.dev

So überprüfen Sie, ob ein Objekt in C # serialisierbar ist

Ich suche nach einer einfachen Möglichkeit, um zu überprüfen, ob ein Objekt in C # serialisierbar ist.

Wie wir wissen, können Sie ein Objekt serialisierbar machen, indem Sie entweder die Schnittstelle ISerializable implementieren oder [Serializable] am Anfang der Klasse platzieren.

Was ich suche, ist eine schnelle Möglichkeit, dies zu überprüfen, ohne die Klasse reflektieren zu müssen, um ihre Attribute zu erhalten. Die Schnittstelle wäre schnell mit einer is Anweisung.

Mit @ Flards Vorschlag ist dies der Code, den ich mir ausgedacht habe. Schrei, es gibt einen besseren Weg.

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

Oder noch besser: Rufen Sie einfach den Typ des Objekts ab und verwenden Sie dann die IsSerializable-Eigenschaft für den Typ:

typeof(T).IsSerializable

Denken Sie daran, dass dies anscheinend nur die Klasse ist, mit der wir uns befassen, wenn die Klasse andere Klassen enthält, die Sie wahrscheinlich alle überprüfen möchten, oder versuchen Sie, sie zu serialisieren und auf Fehler zu warten, wie @pb gezeigt hat.

92
FryHard

Sie haben eine schöne Eigenschaft in der Klasse Type mit dem Namen IsSerializable.

113
leppie

Sie müssen alle Typen im Diagramm der zu serialisierenden Objekte auf das serialisierbare Attribut überprüfen. Am einfachsten ist es, das Objekt zu serialisieren und die Ausnahme abzufangen. (Aber das ist nicht die sauberste Lösung). Type.IsSerializable und die Überprüfung des Attributs serializalbe berücksichtigen das Diagramm nicht.

Probe

[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

Dies ist eine alte Frage, die möglicherweise für .NET 3.5+ aktualisiert werden muss. Type.IsSerializable kann tatsächlich false zurückgeben, wenn die Klasse das DataContract-Attribut verwendet. Hier ist ein Ausschnitt, den ich benutze, wenn es stinkt, lass es mich wissen :)

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

Verwenden Sie Type.IsSerializable, wie andere bereits betont haben.

Es lohnt sich wahrscheinlich nicht, zu versuchen, zu reflektieren und zu überprüfen, ob alle Elemente im Objektdiagramm serialisierbar sind.

Ein Member könnte als serialisierbarer Typ deklariert, aber tatsächlich als abgeleiteter Typ instanziiert werden, der nicht serialisierbar ist, wie im folgenden erfundenen Beispiel:

[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

Selbst wenn Sie feststellen, dass eine bestimmte Instanz Ihres Typs serialisierbar ist, können Sie daher im Allgemeinen nicht sicher sein, dass dies für alle Instanzen zutrifft.

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

Vermutlich beinhaltet Reflexion unter Wasser, aber der einfachste Weg?

6
Grad van Horck

Hier ist eine 3.5-Variante, die es allen Klassen mit einer Erweiterungsmethode zur Verfügung stellt.

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

Ich habe die Antwort auf diese Frage und die Antwort hier übernommen und geändert, sodass Sie eine Liste von Typen erhalten, die nicht serialisierbar sind. Auf diese Weise können Sie leicht erkennen, welche Sie markieren müssen.

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

Und dann nennst du es ...

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

Wenn es ausgeführt wird, enthält nonSerializableTypes die Liste. Möglicherweise gibt es eine bessere Möglichkeit, als eine leere Liste an die rekursive Methode zu übergeben. Wenn ja, korrigiert mich jemand.

2
Andy Merrick

Meine Lösung in VB.NET:

Für Objekte:

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

Für Typen:

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

Das Ausnahmeobjekt ist möglicherweise serialisierbar, verwendet jedoch eine andere Ausnahme, die es nicht ist. Das hatte ich gerade mit WCF System.ServiceModel.FaultException: FaultException ist serialisierbar, ExceptionDetail jedoch nicht!

Also benutze ich folgendes:

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