Как я могу добавить ограничение типа, чтобы включить что-либо сериализуемое в общий метод?

Мой общий метод должен сериализовать переданный ему объект, однако простое настаивание на том, что он реализует ISerializable, похоже, не работает. Например, у меня есть структура, возвращенная из веб-службы (помеченная атрибутом 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);
}

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

Если это невозможно, как лучше всего проверить сериализуемость объекта во время выполнения?


person Matt Brindley    schedule 03.06.2009    source источник


Ответы (4)


Вы не можете сделать это полностью с помощью общих ограничений, но вы можете сделать пару вещей, чтобы помочь:

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

Конечно, по-прежнему существует возможность возникновения исключений во время выполнения при попытке сериализации типа, но это охватывает наиболее очевидные проблемы.

person Adam Sills    schedule 03.06.2009
comment
Этот ответ неверен, так как он даст ложные срабатывания. typeof(T) оценивается как System.Runtime.Type, который является ISerializable, поэтому он всегда будет оцениваться как true. Вместо этого используйте это... if (!typeof(T).IsSerializable && !(typeof(ISerializable).IsAssignableFrom(typeof(T)))) - person Daniel Dyson; 17.07.2012
comment
где T : new() исключает System.Tuple‹›, помеченные атрибутом Serializable. - person kerem; 16.04.2014
comment
Верно, но это все еще кажется довольно безопасным. Большинство людей даже не знают, что такое кортеж, не говоря уже о том, что существует класс .NET Tuple‹T1.....T7›. Кроме того, Tuple в любом случае будет сериализоваться только с двоичной сериализацией (без XML), потому что у него нет ctor по умолчанию. - person Adam Sills; 16.04.2014

Я написал длинную статью в блоге на эту тему, которая может быть вам полезна. В основном это относится к двоичной сериализации, но концепции применимы практически к любому формату сериализации.

Длинное и короткое из этого

  • Невозможно добавить надежное универсальное ограничение
  • Единственный способ проверить и убедиться, что объект был сериализуемым, — это сериализовать его и посмотреть, успешно ли выполнена операция.
person JaredPar    schedule 03.06.2009

Единственный способ узнать, является ли объект сериализуемым, — попытаться сериализовать его.

Фактически, вы спрашивали, как определить, является ли тип «сериализуемым», но фактический вопрос будет касаться объектов. Некоторые экземпляры типа могут быть не сериализуемыми, даже если тип помечен как [Serializable]. Например, что, если экземпляр содержит циклические ссылки?

person John Saunders    schedule 03.06.2009

Вместо

XmlSerializer xmlSerializer = новый XmlSerializer (typeof (T));

пытаться

XmlSerializer xmlSerializer = новый XmlSerializer(message.GetType());

person Peter    schedule 03.06.2009