Frage

Ich bin auf der Suche nach einer einfachen Möglichkeit zu überprüfen, ob ein Objekt in C # serialisierbar ist.

Wie wir wissen Sie machen ein Objekt serializable entweder durch die Umsetzung des ISerializable Schnittstelle oder indem die [Serializable] an der Spitze der Klasse.

Was ich suche ist ein schneller Weg, dies zu überprüfen, ohne die Klasse es Attribute erhalten reflektieren zu müssen. Die Schnittstelle wäre schnell mit einer ist Aussage.

Mit @ Flard Vorschlag dies ist der Code, den ich gekommen bin, mit, Schrei ist, gibt es einen besseren Weg.

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

Oder noch besser, nur die Art des Objekts und dann die IsSerializable Eigenschaft von der Art:

typeof(T).IsSerializable

Denken Sie daran, wenn dies das scheint nur nur die Klasse, die wir mit, wenn die Klasse enthält anderen Klassen beschäftigen Sie wahrscheinlich wollen sie alle oder versuchen und serialisiert werden und warten auf Fehler überprüfen, wie @pb hingewiesen.

War es hilfreich?

Lösung

Sie haben ein schönes Anwesen auf der Type Klasse namens IsSerializable.

Andere Tipps

Sie gehen zu müssen, alle Arten in der grafischen Darstellung von Objekten zu überprüfen, für das serializable Attribut serialisiert werden. Der einfachste Weg ist, um zu versuchen, das Objekt zu serialisieren und die Ausnahme abfangen. (Aber das ist nicht die sauberste Lösung). Type.IsSerializable und Kontrolle für das serializalbe Attribut nehmen Sie nicht die grafische Darstellung berücksichtigt.

Beispiel

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

Dies ist eine alte Frage, die für .NET 3.5 und höher aktualisiert werden muß. Type.IsSerializable kann tatsächlich falsch zurück, wenn die Klasse, um das Datacontract Attribut verwendet. Hier ist ein Ausschnitt i verwenden, wenn es stinkt, lassen Sie mich wissen:)

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

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

}

Verwenden Type.IsSerializable wie andere haben darauf hingewiesen.

Es ist wahrscheinlich nicht wert versuchen, zu reflektieren und zu überprüfen, ob alle Mitglieder im Objektgraphen serializable sind.

Ein Mitglied könnte als serializable Typ deklariert werden, aber in der Tat als eine abgeleitete Typ instanziert werden, die nicht serialisierbar, wie in der folgenden erfundene Beispiel ist:

[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

Deshalb, auch wenn Sie feststellen, dass eine bestimmte Instanz des Typs serialisierbar ist, können Sie in der Regel nicht sicher sein, diese von allen Instanzen wahr sein werden.

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

Wahrscheinlich beinhaltet Reflexion unter Wasser, aber der einfachste Weg?

Hier ist ein 3.5 Variante, die es zur Verfügung zu allen Klassen einer Erweiterungsmethode macht.

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

Ich habe die Antwort auf diese Frage und die Antwort hier und modifiziert es so erhalten Sie eine Liste von Typen, die nicht serialisierbar sind. Auf diese Weise können Sie einfach, welche davon wissen zu markieren.

    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 du es dann rufen ...

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

Wenn es läuft, nonSerializableTypes wird die Liste haben. Es kann ein besserer Weg, dies zu tun, als in einer leeren Liste an die rekursive Methode übergeben. Jemand korrigieren Sie mich, wenn so.

Das Ausnahmeobjekt sein könnte serializable, aber eine andere Ausnahme verwendet, die keine ist. Das ist, was ich hatte nur mit WCF System.ServiceModel.FaultException: FaultException ist serializable aber ExceptionDetail ist nicht

So verwende ich die folgenden:

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

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top