C#如何判断一个对象是否可以序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/81674/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 11:19:52  来源:igfitidea点击:

How to check if an object is serializable in C#

提问by FryHard

I am looking for an easy way to check if an object in C# is serializable.

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

As we know you make an object serializable by either implementing the ISerializableinterface or by placing the [Serializable]at the top of the class.

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

What I am looking for is a quick way to check this without having to reflect the class to get it's attributes. The interface would be quick using an isstatement.

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

Using @Flard's suggestion this is the code that I have come up with, scream is there is a better way.

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

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

Or even better just get the type of the object and then use the IsSerializable property on the type:

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

typeof(T).IsSerializable

Remember though this this seems to only just the class that we are dealing with if the class contains other classes you probably want to check them all or try and serialize and wait for errors as @pb pointed out.

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

采纳答案by leppie

You have a lovely property on the Typeclass called IsSerializable.

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

回答by Grad van Horck

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

Probably involves reflection underwater, but the most simple way?

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

回答by Paul van Brenk

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.

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

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

回答by Michael Meadows

Here's a 3.5 variation that makes it available to all classes using an extension method.

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

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

回答by Joe

Use Type.IsSerializable as others have pointed out.

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

It's probably not worth attempting to reflect and check if all members in the object graph are serializable.

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

A member could be declared as a serializable type, but in fact be instantiated as a derived type that is not serializable, as in the following contrived example:

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

[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

Therefore, even if you determine that a specific instance of your type is serializable, you can't in general be sure this will be true of all instances.

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

回答by Mike_G

This is an old question, that may need to be updated for .NET 3.5+. Type.IsSerializable can actually return false if the class uses the DataContract attribute. Here is a snippet i use, if it stinks, let me know :)

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

}

回答by Eric

The exception object might be serializable , but using an other exception which is not. This is what I just had with WCF System.ServiceModel.FaultException: FaultException is serializable but ExceptionDetail is not!

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

So I am using the following:

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

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

回答by sewershingle

I took the answer on this question and the answer hereand modified it so you get a List of types that aren't serializable. That way you can easily know which ones to mark.

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

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

And then you call it...

然后你叫它...

    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.

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

回答by ElektroStudios

My solution, in VB.NET:

我的解决方案,在 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