Универсальный вспомогательный класс сериализации C # - PullRequest
6 голосов
/ 20 июля 2010

У меня есть класс для сериализации и десериализации объектов в / из XML.Это универсальный класс с одним параметром типа T, единственным ограничением которого является where T : IXmlSerializable.Однако я все еще хочу использовать этот класс для классов, которые не реализуют IXmlSerializable, но имеют атрибут [Serializable].Как я мог сделать это?

Из моего общего класса:

public static class XmlSerializationUtils<T> where T : IXmlSerializable
{
    public static T DeserializeXml(XmlDocument xml) { ... }
    public static XmlDocument SerializeToXml(T toSerialize) { ... }
}

Я нашел это обсуждение , но не было дано никакого решения, только то, что я могу 'сделать where T : Serializable.Попытка сделать where T : SerializableAttribute заставляет Visual Studio сказать "Невозможно использовать запечатанный класс 'System.SerializableAttribute' в качестве ограничения параметра типа".

Редактировать: на основе ответ Стивена Я удалил ограничения на XmlSerializationUtils<T> и добавил статический конструктор:

static XmlSerializationUtils()
{
    Type type = typeof(T);
    bool hasAttribute = null != Attribute.GetCustomAttribute(type,
        typeof(SerializableAttribute));
    bool implementsInterface =
        null != type.GetInterface(typeof(IXmlSerializable).FullName);
    if (!hasAttribute && !implementsInterface)
    {
        throw new ArgumentException(
            "Cannot use XmlSerializationUtils on class " + type.Name +
            " because it does not have the Serializable attribute " +
            " and it does not implement IXmlSerializable"
        );
    }
}

Ответы [ 3 ]

8 голосов
/ 20 июля 2010

Вы можете проверить, является ли тип сериализуемым, используя свойство IsSerializable Типа объекта.

myObj.GetType().IsSerializable

Как уже упоминалось, добавить его какобщее ограничение, но, скорее всего, будет проверено в конструкторе.

6 голосов
/ 20 июля 2010

Вы не можете требовать атрибут как часть обобщений.Однако вы можете предоставить статический конструктор, который проверяет его и выдает, если он не найден.

5 голосов
/ 20 июля 2010

Я бы просто удалил ограничение типа и перехватил бы исключение SerializationException, когда тип не сериализуется и не десериализуется должным образом ... Фактически, это позволяет вашим универсальным методам Serialize и Deserialize принимать форматтер

public enum Formatter { Binary, Xml }

, который может контролировать, является ли сериализация двоичной или Xml

public class Serialization
{
    public enum Formatter { Binary, Xml }

    #region Serialization methods
    public static void Serialize2File<T>(T obj, string pathSpec, 
        Formatter formatter)
    {
        try
        {
            switch (formatter)
            {
                case (Formatter.Binary):
                    using (var fs = new FileStream(pathSpec, FileMode.Create,
                                        FileAccess.Write, FileShare.Write))
                        (new BinaryFormatter()).Serialize(fs, obj);
                    break;

                case (Formatter.Xml):
                    var serializer = new XmlSerializer(typeof(T));
                    TextWriter textWriter = new StreamWriter(pathSpec);
                    serializer.Serialize(textWriter, obj);
                    textWriter.Close();
                    break;

                default:
                    throw new MyCustomException("Invalid Formatter option");
            }
        }
        catch (SerializationException sX)
        {
            var errMsg = String.Format(
                "Unable to serialize {0} into file {1}",
                obj, pathSpec);
            throw new MyCustomException(errMsg, sX);
        }
    }
    public static T DeSerializeFromFile<T>(string pathSpec, 
        Formatter formatter) where T : class
    {
        try
        {
            switch (formatter)
            {
                case (Formatter.Binary):
                    using (var strm = new FileStream(pathSpec,
                                        FileMode.Open, FileAccess.Read))
                    {
                        IFormatter fmt = new BinaryFormatter();
                        var o = fmt.Deserialize(strm);
                        if (!(o is T))
                            throw new ArgumentException("Bad Data File");
                        return o as T;
                    }

                case (Formatter.Xml):
                    var serializer = new XmlSerializer(typeof(T));
                    TextReader rdr = new StreamReader(pathSpec);
                    return (T)serializer.Deserialize(rdr);

                default:
                    throw new MyCustomException("Invalid Formatter option");
            }
        }
        catch (SerializationException sX)
        {
            var errMsg = String.Format(
                "Unable to deserialize {0} from file {1}",
                typeof(T), pathSpec);
            throw new MyCustomException(errMsg, sX);
        }
    }
    #endregion Serialization methods
}
...