ti-enxame.com

Como verificar se um objeto é serializável em c #

Estou procurando uma maneira fácil de verificar se um objeto em C # é serializável.

Como sabemos, você torna um objeto serializável implementando a interface ISerializable ou colocando o [Serializable] na parte superior da classe.

O que estou procurando é uma maneira rápida de verificar isso sem precisar refletir a classe para obter seus atributos. A interface seria rápida usando uma declaração is.

Usando a sugestão de @ Flard, este é o código que eu criei, grite: existe uma maneira melhor.

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

Ou melhor ainda, obtenha o tipo do objeto e use a propriedade IsSerializable no tipo:

typeof(T).IsSerializable

Lembre-se de que isso parece apenas a classe com a qual estamos lidando, se a classe contiver outras classes com as quais você provavelmente deseja verificar todas elas ou tentar serializar e aguardar erros, como @pb apontou.

92
FryHard

Você tem uma propriedade adorável na classe Type chamada IsSerializable.

113
leppie

Você precisará verificar todos os tipos no gráfico de objetos que estão sendo serializados para o atributo serializable. A maneira mais fácil é tentar serializar o objeto e capturar a exceção. (Mas essa não é a solução mais limpa). Type.IsSerializable e a verificação do atributo serializalbe não levam em consideração o gráfico.

Amostra

[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

Esta é uma pergunta antiga, que talvez precise ser atualizada para o .NET 3.5+. Type.IsSerializable pode realmente retornar false se a classe usar o atributo DataContract. Aqui está um trecho que eu uso, se cheira mal, me avise :)

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

Use Type.IsSerializable como outros indicaram.

Provavelmente não vale a pena tentar refletir e verificar se todos os membros no gráfico de objetos são serializáveis.

Um membro pode ser declarado como um tipo serializável, mas, de fato, ser instanciado como um tipo derivado que não é serializável, como no seguinte exemplo artificial:

[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

Portanto, mesmo se você determinar que uma instância específica do seu tipo é serializável, em geral não é possível garantir que isso seja verdade para todas as instâncias.

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

Provavelmente envolve reflexão debaixo d'água, mas a maneira mais simples?

6
Grad van Horck

Aqui está uma variação de 3,5 que o torna disponível para todas as classes usando um método de extensão.

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

Peguei a resposta nesta questão e a resposta aqui e a modifiquei para obter uma lista de tipos que não são serializáveis. Dessa forma, você pode saber facilmente quais 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))));
    }

E então você chama ...

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

Quando executado, nonSerializableTypes terá a lista. Pode haver uma maneira melhor de fazer isso do que passar uma lista vazia para o método recursivo. Alguém me corrija se sim.

2
Andy Merrick

Minha solução, no 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
0
ElektroStudios

O objeto de exceção pode ser serializável, mas usando uma outra exceção que não é. Isto é o que eu tinha com o WCF System.ServiceModel.FaultException: FaultException é serializável, mas ExceptionDetail não é!

Então, eu estou usando o seguinte:

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