96

我正在寻找一种简单的方法来检查 C# 中的对象是否可序列化。

正如我们所知,您可以通过实现ISerializable接口或将[Serializable]放在类的顶部来使对象可序列化。

我正在寻找的是一种快速检查这一点的方法,而无需反映类来获取它的属性。使用is语句,界面会很快。

使用@Flard 的建议,这是我想出的代码,尖叫是否有更好的方法。

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

或者更好的是获取对象的类型,然后在类型上使用 IsSerializable 属性:

typeof(T).IsSerializable

请记住,虽然这似乎只是我们正在处理的类,如果该类包含其他类,您可能想要全部检查它们或尝试序列化并等待@pb 指出的错误。

4

9 回答 9

121

你在类上有一个可爱的属性,Type叫做IsSerializable.

于 2008-09-17T10:20:08.773 回答
43

您将不得不检查正在序列化的对象图中的所有类型以获取可序列化属性。最简单的方法是尝试序列化对象并捕获异常。(但这不是最干净的解决方案)。Type.IsSerializable 和检查 serializalbe 属性不考虑图形。

样本

[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);
    }
}
于 2008-09-17T10:13:30.863 回答
18

这是一个老问题,可能需要针对 .NET 3.5+ 进行更新。如果类使用 DataContract 属性,Type.IsSerializable 实际上可以返回 false。这是我使用的一个片段,如果它很臭,请告诉我:)

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

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

}
于 2010-10-27T21:22:32.553 回答
9

正如其他人指出的那样,使用 Type.IsSerializable 。

可能不值得尝试反映和检查对象图中的所有成员是否都是可序列化的。

可以将成员声明为可序列化类型,但实际上将其实例化为不可序列化的派生类型,如以下人为设计的示例:

[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

因此,即使您确定您的类型的特定实例是可序列化的,通常也不能确定所有实例都是如此。

于 2008-09-17T11:46:14.823 回答
6
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

可能涉及水下反射,但最简单的方法是什么?

于 2008-09-17T10:12:21.523 回答
5

这是一个 3.5 变体,使用扩展方法使其可用于所有类。

public static bool IsSerializable(this object obj)
{
    if (obj is ISerializable)
        return true;
    return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute));
}
于 2008-09-17T10:29:15.540 回答
2

我接受了这个问题的答案和这里的答案并对其进行了修改,以便您获得一个不可序列化的类型列表。这样你就可以很容易地知道要标记哪些。

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

然后你叫它...

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

当它运行时,nonSerializableTypes 将拥有该列表。可能有比将空列表传递给递归方法更好的方法。如果是这样,有人纠正我。

于 2012-10-24T17:25:48.403 回答
1

我的解决方案,在 VB.NET 中:

对于对象:

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

对于类型:

''' <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
于 2014-08-02T15:24:33.817 回答
0

异常对象可能是可序列化的,但使用另一个不是的异常。这就是我刚刚使用 WCF System.ServiceModel.FaultException: FaultException 是可序列化的,但 ExceptionDetail 不是!

所以我正在使用以下内容:

// 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);
    }
于 2011-05-06T14:43:20.537 回答