Wie kann man überprüfen, ob ein Objekt serialisierbar in C #
-
09-06-2019 - |
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.
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