如何在 C # 中检查对象是否可序列化

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

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

我正在寻找的是一种快速的方法来检查这一点,而不必反映类得到它的属性。使用 语句可以快速实现接口。

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

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

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

typeof(T).IsSerializable

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

72654 次浏览
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

Probably involves reflection underwater, but the most simple way?

You're going to have to check all types in the graph of objects being serialized for the serializable attribute. The easiest way is to try to serialize the object and catch the exception. (But that's not the cleanest solution). Type.IsSerializable and checking for the serializalbe attribute don't take the graph into account.

Sample

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

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

下面是一个3.5版本的变体,它使所有使用扩展方法的类都可以使用它。

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

正如其他人指出的那样,使用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

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

这是一个老问题,可能需要针对.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)


}

异常对象可能是可序列化的,但使用了另一个不可序列化的异常。 这是我刚刚用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);
}

我把这个问题的答案和答案在这里进行了修改,这样你就可以得到一个不可序列化的类型列表。这样,您就可以轻松地知道要标记哪些。

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

When it runs, nonSerializableTypes will have the list. There may be a better way of doing this than passing in an empty List to the recursive method. Someone correct me if so.

My solution, in VB.NET:

For Objects:

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

For Types:

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