web-dev-qa-db-ja.com

ジェネリックメソッドにシリアル化可能なものを含めるために型制約を追加するにはどうすればよいですか?

私のジェネリックメソッドは、渡されたオブジェクトをシリアル化する必要がありますが、ISerializableを実装していると主張するだけでは機能しないようです。たとえば、xmlにシリアル化するWebサービス(SerializableAttributeでマークされている)から返された構造体がありますが、予想どおり、C#コンパイラは文句を言います。

オブジェクトをシリアル化する前に、オブジェクトがシリアル化可能であることを確認する方法はありますか、それとも、whereキーワードを使用してオブジェクトが適切かどうかを確認する方法はありますか?

これが私の完全な方法です:

public static void Push<T>(string url, T message)
        where T : ISerializable
{
    string xml = SerializeMessage(message);

    // Send the message to Amazon SQS
    SendMessageRequest sendReq = new SendMessageRequest { QueueUrl = url, MessageBody = xml };
    AmazonSQSClient client = new AmazonSQSClient(S3User, S3Pass);
    client.SendMessage(sendReq);
}

そしてSerializeMessage:

private static string SerializeMessage<T>(T message)
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
    using (StringWriter stringWriter = new StringWriter())
    {
        xmlSerializer.Serialize(stringWriter, message);
        return stringWriter.ToString();
    }
}

これが不可能な場合、実行時にオブジェクトがシリアル化可能であることを確認するための最良の方法は何ですか?

43
Matt Brindley

一般的な制約を介してこれを完全に行うことはできませんが、役立つことがいくつかあります。

1)ジェネリック型にnew()制約を設定します(逆シリアル化機能を有効にし、XmlSerializerがデフォルトのctorの欠如について文句を言わないようにするため):

where T : new()

2)シリアル化を処理するメソッドの最初の行(またはコンストラクター、またはそれを何度も繰り返す必要がない他の場所)で、次のチェックを実行できます。

if( !typeof(T).IsSerializable && !(typeof(ISerializable).IsAssignableFrom(typeof(T)) ) )
    throw new InvalidOperationException("A serializable Type is required");

もちろん、型をシリアル化しようとするとランタイム例外が発生する可能性はありますが、これは最も明白な問題をカバーします。

39
Adam Sills

私はあなたが役に立つと思うかもしれないこの主題に関する長さのブログ記事を書きました。これは主にバイナリシリアル化に使用されますが、概念はほとんどすべてのシリアル化形式に適用できます。

それの長短は

  • 信頼できるジェネリック制約を追加する方法はありません
  • オブジェクトシリアル化可能かどうかを確認する唯一の方法は、オブジェクトをシリアル化して、操作が成功するかどうかを確認することです。
10
JaredPar

オブジェクトがシリアル化可能かどうかを知る唯一の方法は、オブジェクトをシリアル化しようとすることです。

実際、タイプが「シリアル化可能」であるかどうかを判断する方法を尋ねていましたが、実際の質問はオブジェクトに関するものです。タイプが[Serializable]とマークされていても、タイプの一部のインスタンスはシリアル化できない場合があります。たとえば、インスタンスに循環参照が含まれている場合はどうなりますか?

3
John Saunders

の代わりに

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

試してみてください

XmlSerializer xmlSerializer = new XmlSerializer(message.GetType());

0
Peter