44

我的通用方法需要序列化传递给它的对象,但是仅仅坚持它实现 ISerializable 似乎不起作用。例如,我有一个从 Web 服务(标有 SerializableAttribute)返回的结构,它可以很好地序列化为 xml,但是,正如预期的那样,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);
}

和序列化消息:

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

如果这不可能,那么在运行时检查对象是否可序列化的最佳方法是什么?

4

5 回答 5

41

您不能完全通过通用约束来做到这一点,但您可以做几件事来提供帮助:

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

当然,尝试序列化类型时仍然可能出现运行时异常,但这将涵盖最明显的问题。

于 2009-06-03T15:50:55.283 回答
11

我写了一篇关于这个主题的长篇博客文章,您可能会觉得有帮助。它主要涉及二进制序列化,但这些概念适用于大多数任何序列化格式。

它的长短是

  • 没有办法添加可靠的通用约束
  • 检查对象是否可序列化的唯一方法是对其进行序列化并查看操作是否成功
于 2009-06-03T15:47:43.193 回答
4

知道一个对象是否可序列化的唯一方法是尝试序列化它。

实际上,您是在问如何判断一个类型是否“可序列化”,但实际问题是关于对象的。即使类型标记为 [Serializable],某些类型的实例也可能无法序列化。例如,如果实例包含循环引用怎么办?

于 2009-06-03T15:48:56.423 回答
0

代替

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

尝试

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

于 2009-06-03T15:47:32.053 回答
0

C# 8 及更高版本允许unmanaged约束将类型限制为仅包含值类型的结构(在任何嵌套级别上)。我们真正想要的是:

public class MyClass<T> where T : ISerializable or unmanaged

但不幸的是,在编写 C# 时不支持这种语法(约束总是 AND,用逗号分隔)。

解决方法可能是 ValueWrapper 类:

public class ValueWrapper<U> : ISerializable where U : unmanaged

这需要一个 U 作为构造函数参数。它有一个属性U Value。现在,您可以将值类型视为 ISerializable,只需将它们包装在 ValueWrapper 中即可。

于 2021-12-11T23:18:14.197 回答