Pergunta

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

Como sabemos, você torna um objeto serializável implementando o ISerializável interface ou colocando o [Serializável] no topo 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 um é declaração.

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

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

Ou melhor ainda, basta obter o tipo do objeto e usar a propriedade IsSerializable no tipo:

typeof(T).IsSerializable

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

Foi útil?

Solução

Você tem uma bela propriedade na classe Type chamado IsSerializable.

Outras dicas

Você vai ter que verificar todos os tipos no gráfico de objetos sendo serializado para o atributo serializable. A maneira mais fácil é tentar serializar o objeto e capturar a exceção. (Mas isso não é a solução mais limpa). Type.IsSerializable e verificação para o atributo serializalbe não tomar o gráfico em conta.

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

Esta é uma velha questão, que pode precisar ser atualizado para .NET 3.5+. Type.IsSerializable pode realmente retornar false se a classe usa o atributo DataContract. Aqui está um trecho eu uso, se ele fede, deixe-me saber:)

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

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

}

Use Type.IsSerializable como outros apontaram.

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

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

[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 de seu tipo é serializável, você não pode nos ser geral certeza que isso vai ser verdade para todas as instâncias.

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

Provavelmente envolve reflexão subaquática, mas a forma mais simples?

Aqui está uma variação 3.5 que 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));
}

Eu levei a resposta sobre esta questão ea resposta aqui e modificado de modo a obter uma lista de tipos que não são serializado. Dessa forma, você pode facilmente saber quais marca.

    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ê chamá-lo ...

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

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

O objeto de exceção pode ser serializável, mas utilizando 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);
    }

A minha solução, em 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top