Szukam łatwego sposobu sprawdzenia, czy obiekt w C # jest możliwy do serializacji.
Jak wiemy, obiekt nadaje się do serializacji poprzez implementację interfejsu ISerializable lub umieszczenie [Serializable] na szczycie klasy.
To, czego szukam, to szybki sposób sprawdzenia tego bez konieczności odzwierciedlania klasy, aby uzyskać jej atrybuty. Interfejs byłby szybki przy użyciu instrukcji is .
Korzystając z sugestii @ Flarda, oto kod, który wymyśliłem, krzyk, czy 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ę, że jest to tylko klasa, z którą mamy do czynienia, jeśli klasa zawiera inne klasy, prawdopodobnie chcesz je wszystkie sprawdzić lub spróbować serializować i poczekać na błędy, jak wskazał @pb.
źródło
Odpowiedzi:
Masz cudowną posiadłość w
Type
klasie o nazwieIsSerializable
.źródło
Będziesz musiał sprawdzić wszystkie typy na wykresie serializowanych obiektów dla atrybutu możliwego do serializacji. Najłatwiejszym sposobem jest próba serializacji obiektu i przechwycenie wyjątku. (Ale to nie jest najczystsze rozwiązanie). Type.IsSerializable i sprawdzanie atrybutu serializalbe nie bierze pod uwagę wykresu.
Próba
[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); } }
źródło
To stare pytanie, które może wymagać aktualizacji dla .NET 3.5+. Type.IsSerializable może faktycznie zwrócić false, jeśli klasa używa atrybutu DataContract. Oto fragment, którego używam, jeśli śmierdzi, daj mi znać :)
public static bool IsSerializable(this object obj) { Type t = obj.GetType(); return Attribute.IsDefined(t, typeof(DataContractAttribute)) || t.IsSerializable || (obj is IXmlSerializable) }
źródło
null
sprawdź i wróć, jeślitrue
?Użyj Type.IsSerializable, jak wskazali inni.
Prawdopodobnie nie warto próbować odzwierciedlać i sprawdzać, czy wszystkie elementy składowe w grafie obiektów są możliwe do serializacji.
Element członkowski może być zadeklarowany jako typ możliwy do serializacji, ale w rzeczywistości może zostać utworzony jako typ pochodny, którego nie można serializować, jak w następującym wymyślonym 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 określone wystąpienie Twojego typu jest możliwe do serializacji, nie możesz ogólnie mieć pewności, że będzie to prawdą dla wszystkich wystąpień.
źródło
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));
Prawdopodobnie wymaga odbicia pod wodą, ale najprostszy sposób?
źródło
Oto odmiana 3,5, która udostępnia ją wszystkim klasom przy użyciu metody rozszerzającej.
public static bool IsSerializable(this object obj) { if (obj is ISerializable) return true; return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute)); }
źródło
Wziąłem odpowiedź na to pytanie i odpowiedź tutaj i zmodyfikowałem ją, aby uzyskać listę typów, których nie można serializować. 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)))); }
A potem nazywasz to ...
List<string> nonSerializableTypes = new List<string>(); NonSerializableTypesOfParentType(aType, nonSerializableTypes);
Po uruchomieniu nonSerializableTypes będzie mieć listę. Może być lepszy sposób na zrobienie tego niż przekazanie pustej listy do metody rekurencyjnej. Niech ktoś mnie poprawi, jeśli tak.
źródło
Obiekt wyjątku może być możliwy do serializacji, ale przy użyciu innego wyjątku, który nie jest. Właśnie to miałem z WCF System.ServiceModel.FaultException: FaultException można serializować, ale ExceptionDetail nie jest!
Więc używam następujących:
// 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); }
źródło
Moje rozwiązanie w VB.NET:
W przypadku 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
źródło