C#通用序列化实用程序类

时间:2010-07-20 16:05:58

标签: c# generics xml-serialization constraints

我有一个现有的类,用于对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) { ... }
}

我找到了this discussion,但没有给出解决方案,只是我做不到where T : Serializable。尝试where T : SerializableAttribute使Visual Studio说“不能使用密封类'System.SerializableAttribute'作为类型参数约束”。

基于Stephen's answer

修改,我删除了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 个答案:

答案 0 :(得分:8)

您可以使用对象类型的IsSerializable属性检查类型是否可序列化。

myObj.GetType().IsSerializable

如上所述,这不可能作为通用约束添加,但最有可能在构造函数中检查。

答案 1 :(得分:6)

您不能要求属性作为泛型的一部分。但是,您可以提供一个静态构造函数来检查它,如果找不到则抛出它。

答案 2 :(得分:5)

我只是消除了类型约束并在类型没有正确序列化或反序列化时捕获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
}