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

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

How to check if an object is serializable in C#

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

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

我正在寻找的是一种快速检查方法,而无需反映类以获得它的属性。 接口可以快速使用is语句。

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

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

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

1
typeof(T).IsSerializable

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


你在Type类中有一个名为IsSerializable的可爱属性。


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

样品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
[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);
    }
}


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

1
2
3
4
5
6
7
public static bool IsSerializable(this object obj)
{
    Type t = obj.GetType();

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

}

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[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

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


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

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


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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    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))));
    }

然后你称之为......

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

运行时,nonSerializableTypes将具有该列表。除了将空List传递给递归方法之外,可能有更好的方法。如果有的话,有人纠正我。


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

对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
''' <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

对于类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
''' <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

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

所以我使用以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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);
    }

推荐阅读

    linux反序列化命令?

    linux反序列化命令?,状态,数据,情况,环境,网络,适当,下来,接口,对象,序列,序

    linux检查硬盘的命令?

    linux检查硬盘的命令?,系统,信息,检测,情况,命令,工具,电脑,地址,设备,硬盘,l

    linux检查挂载命令?

    linux检查挂载命令?,设备,系统,信息,情况,状态,服务,软件,命令,磁盘,网络,lin

    linux无效对象的命令?

    linux无效对象的命令?,软件,系统,单位,网络,管理,术语,检测,电脑,环境,风险,l

    linux一般检查命令?

    linux一般检查命令?,网络,系统,检测,情况,工作,信息,命令,进程,时间,设备,lin

    检查硬件linux命令?

    检查硬件linux命令?,信息,系统,第一,数据,设备,检测,命令,情况,灵活,实时,如

    linux查看接口命令?

    linux查看接口命令?,地址,系统,标准,命令,管理,工作,文件,端口,目录,路径,lin

    linux命令查看包属性?

    linux命令查看包属性?,时间,系统,信息,状态,命令,文件,通讯录,管理,情况,标

    检查路由命令linux?

    检查路由命令linux?,网络,地址,系统,信息,工具,电脑,时间,通信,服务,命令,lin

    使用linux命令调接口?

    使用linux命令调接口?,网络,系统,地址,信息,工具,情况,服务,灵活,电脑,名称,

    linux数据库检查命令?

    linux数据库检查命令?,服务,状态,地址,位置,系统,信息,命令,工作,情况,密码,

    linux分区检查命令是?

    linux分区检查命令是?,系统,设备,工具,管理,情况,信息,检测,分区,密码,单位,

    linux检查流量的命令?

    linux检查流量的命令?,工具,系统,实时,状态,网络,信息,数据,密码,地址,流量,l

    linux命令添加接口?

    linux命令添加接口?,地址,网络,名称,系统,工具,设备,信息,服务,中心,密码,Lin

    linux检查更新命令是?

    linux检查更新命令是?,工作,软件,地址,系统,信息,管理,命令,目录,最新,标准,l

    命令检查linux版本?

    命令检查linux版本?,系统,地址,信息,发行,名称,电脑,版本,连续,工具,周期,在L

    linux接口模式命令?

    linux接口模式命令?,设备,系统,信息,网络,工具,端口,服务,数字,地址,情况,Lin

    linux内存检查命令?

    linux内存检查命令?,情况,系统,信息,工具,实时,分析,状态,内存,命令,总量,查

    linux内核属性命令?

    linux内核属性命令?,系统,地址,时间,信息,标准,管理,数据,工作,百分比,内核,

    linux下节点检查命令?

    linux下节点检查命令?,系统,信息,工作,名称,命令,地址,情况,文件,服务,第一,l