Pregunta

Estoy buscando una manera sencilla de comprobar si un objeto en C# es serializable.

Como sabemos, usted hace que un objeto sea serializable implementando el ISerializable interfaz o colocando el [Serializable] en la parte superior de la clase.

Lo que estoy buscando es una forma rápida de comprobar esto sin tener que reflejar la clase para obtener sus atributos.La interfaz sería rápida usando un es declaración.

Usando la sugerencia de @Flard, este es el código que se me ocurrió, grita si hay una manera mejor.

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

O incluso mejor, simplemente obtenga el tipo de objeto y luego use la propiedad IsSerializable en el tipo:

typeof(T).IsSerializable

Sin embargo, recuerde que esto parece ser solo la clase con la que estamos tratando, si la clase contiene otras clases, probablemente desee verificarlas todas o intentar serializarlas y esperar errores como señaló @pb.

¿Fue útil?

Solución

Tienes una hermosa propiedad en el Type clase llamada IsSerializable.

Otros consejos

Tendrá que verificar todos los tipos en el gráfico de objetos que se serializan para el atributo serializable.La forma más sencilla es intentar serializar el objeto y detectar la excepción.(Pero esa no es la solución más limpia).Type.IsSerializable y verificar el atributo serializalbe no tienen en cuenta el gráfico.

Muestra

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

Esta es una pregunta antigua que quizás deba actualizarse para .NET 3.5+.Type.IsSerializable puede devolver falso si la clase usa el atributo DataContract.Aquí hay un fragmento que uso, si huele mal, házmelo saber :)

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

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

}

Utilice Type.IsSerializable como otros han señalado.

Probablemente no valga la pena intentar reflexionar y comprobar si todos los miembros del gráfico de objetos son serializables.

Un miembro podría declararse como un tipo serializable, pero en realidad instanciarse como un tipo derivado que no es serializable, como en el siguiente ejemplo ideado:

[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

Por lo tanto, incluso si determina que una instancia específica de su tipo es serializable, en general no puede estar seguro de que esto será cierto para todas las instancias.

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

Probablemente implique reflexión bajo el agua, pero ¿la forma más sencilla?

Aquí hay una variación 3.5 que la pone a disposición de todas las clases mediante un método de extensión.

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

Tomé la respuesta a esta pregunta y la respuesta aquí y lo modifiqué para que obtenga una Lista de tipos que no son serializables.De esa manera podrás saber fácilmente cuáles marcar.

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

Y luego lo llamas...

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

Cuando se ejecute, nonSerializableTypes tendrá la lista.Puede haber una mejor manera de hacer esto que pasar una Lista vacía al método recursivo.Que alguien me corrija si es así.

El objeto de excepción puede ser serializable, pero utiliza otra excepción que no lo es.Esto es lo que acabo de tener con WCF System.ServiceModel.FaultException:¡FaultException es serializable pero ExceptionDetail no!

Entonces estoy usando lo siguiente:

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

Mi solución, en VB.NET:

Para objetos:

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

Para tipos:

''' <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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top