オブジェクトがC#でシリアル化可能かどうかを確認する方法


94

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が指摘したようにシリアル化してエラーを待機する必要があります。


1
objのフィールドがシリアル化可能でない場合は失敗します。サンプルを参照してください。
ポールファンブレンク

:私はこれがずっと良いアプローチだと思うstackoverflow.com/questions/236599/...
Xeroなど

「ISerializableインターフェイスを実装するか、[Serializable]をクラスの先頭に配置することにより、オブジェクトをシリアル化可能にする」という記述は誤りです。オブジェクトを直列化可能にするには、そのクラスでSerializableAttributeを宣言する必要があります。ISerializableを実装すると、プロセスをより詳細に制御できるようになります。
Mishax 2013

回答:


115

Typeと呼ばれるクラスに素敵なプロパティがありIsSerializableます。


7
これは、Serializableの属性がクラスにアタッチされているかどうかを通知するだけです。
Fatema

37
彼のポイントは、そのオブジェクトのメンバーは、含まれている型がシリアライズ可能でなくても、シリアライズできない可能性があるということです。正しい?それをシリアル化して失敗するかどうかを確認するだけでなく、そのオブジェクトメンバーを再帰的にドリルしてそれぞれをチェックする必要があるのではありませんか?
ブライアンスウィーニー

3
たとえば、List <SomeDTO>の場合、SomeDTOがシリアル化可能でない場合でも、IsSerializableはtrueです
Simon Dowdeswell

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

コストがそれほど高くないなら、私はこのアプローチが最良だと思います。さまざまなシリアル化要件(バイナリ、xml)をチェックできます。また、オブジェクトには、シリアル化を中断し、実行時に変更される可能性のある継承されたクラス型と交換できる汎用メンバーがある場合があります。List(Of baseclass)には、baseclassとsubclassBがシリアル化可能なsubclassAのアイテムを追加できます。
投票コーヒー

この回答では、複製を使用して、シリアル化がラウンドトリップできるかどうかを確認します。:シリアル化は一部のメンバーを設定することが予想されていないたけれどもそれはいくつかのケースではやり過ぎかもしれstackoverflow.com/questions/236599/...
VoteCoffee

18

これは古い質問です。.NET3.5以降では更新が必要になる場合があります。Type.IsSerializableは、クラスがDataContract属性を使用している場合、実際にはfalseを返すことができます。ここに私が使用するスニペットがあります、それが悪臭を放つなら、私に知らせてください:)

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

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

}

1
古い質問と古い答えですが、これは非常に本当です!Type.IsSerializableは、部分的に機能するソリューションにすぎません。実際、最近のWCFとDataContractsの使用数を考えると、実際には非常に貧弱なソリューションです。
Jaxidian

objがnullとして入ってくるとどうなりますか?
N73k

@ N73kはnullチェックして戻りtrueますか?
FredM

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

したがって、タイプの特定のインスタンスがシリアル化可能であると判断した場合でも、一般に、これがすべてのインスタンスに当てはまるかどうかはわかりません。



5

拡張メソッドを使用してすべてのクラスで使用できるようにする3.5のバリエーションを次に示します。

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

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にリストがあります。これを行うには、空のリストを再帰的メソッドに渡すよりも良い方法があるかもしれません。もしそうなら誰かが私を訂正します。


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

0

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.