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

Sar*_*els 6 c# generics constraints xml-serialization

我有一个现有的类,用于序列化和反序列化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) { ... }
}
Run Code Online (Sandbox Code Playgroud)

我发现了这个讨论,但没有给出解决方案,只是我做不到where T : Serializable.试图做的where T : SerializableAttribute是使Visual Studio说"不能使用密封类'System.SerializableAttribute'作为类型参数约束".

编辑:根据Stephen的回答,我删除了约束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"
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

wom*_*omp 8

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

myObj.GetType().IsSerializable
Run Code Online (Sandbox Code Playgroud)

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


Ste*_*dit 6

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


Cha*_*ana 6

我只是消除了类型约束并在类型没有正确序列化或反序列化时捕获SerializationException ...实际上,这允许您的通用Serialize和Deserialize方法接受格式化程序

public enum Formatter { Binary, Xml }
Run Code Online (Sandbox Code Playgroud)

这可以控制序列化是二进制还是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
}
Run Code Online (Sandbox Code Playgroud)