【问题标题】:Serializing a class with a generic Enum that can be different Enum types使用可以是不同 Enum 类型的通用 Enum 序列化类
【发布时间】:2017-05-13 16:41:01
【问题描述】:

我正在尝试设计一个允许用户在 XML 中指定枚举类型的应用程序,然后应用程序将执行与该枚举相关的特定方法(使用字典)。我被 XML 的 Enum 部分挂断了。

public class TESTCLASS
{
    private Enum _MethodType;

    [XmlElement(Order = 1, ElementName = "MethodType")]
    public Enum MethodType
    {
        get { return _MethodType; }
        set { _MethodType = value; } 
    }
    public TESTCLASS() { }

    public TESTCLASS(Enummies.BigMethods bigM)
    {
        MethodType = bigM;
    }
    public TESTCLASS(Enummies.SmallMethods smallM)
    {
        MethodType = smallM;
    }
}

public class Enummies
{
    public enum BigMethods { BIG_ONE, BIG_TWO, BIG_THREE }
    public enum SmallMethods { SMALL_ONE, SMALL_TWO, SMALL_THREE }
}

然后尝试序列化 TESTCLASS 会导致异常:

string p = "C:\\testclass.xml";
TESTCLASS testclass = new TESTCLASS(Enummies.BigMethods.BIG_ONE);
TestSerializer<TESTCLASS>.Serialize(p, testclass);

System.InvalidOperationException: The type Enummies+BigMethods may not be used in this context.

我的序列化方法是这样的:

public class TestSerializer<T> where T: class
{
    public static void Serialize(string path, T type)
    {
        var serializer = new XmlSerializer(type.GetType());
        using (var writer = new FileStream(path, FileMode.Create))
        {
            serializer.Serialize(writer, type);
        }
    }

    public static T Deserialize(string path)
    {
        T type;
        var serializer = new XmlSerializer(typeof(T));
        using (var reader = XmlReader.Create(path))
        {
            type = serializer.Deserialize(reader) as T;
        }
        return type;
    }
}

我尝试在 MethodType Getter 中包含一些检查/转换,但这会导致相同的错误。

    public Enum MethodType
    {
        get 
        { 
            if (_MethodType is Enummies.BigMethods) return (Enummies.BigMethods)_MethodType; 
            if (_MethodType is Enummies.SmallMethods) return (Enummies.SmallMethods)_MethodType;
            throw new Exception("UNKNOWN ENUMMIES TYPE");
        }
        set { _MethodType = value; } 
    }

【问题讨论】:

  • 您是否提前知道可能存在哪些枚举类型?

标签: c# serialization enums


【解决方案1】:

当我尝试使用XmlSerializer 序列化您的课程时,我得到的最里面的异常是:

Message="System.Enum is an unsupported type. Please use [XmlIgnore] attribute to exclude members of this type from serialization graph."

这是不言自明的:您不能序列化类型为抽象类型 System.Enum 的成员。

但是,您可以序列化 System.Object 类型的成员 前提是所有可能遇到的值类型都使用 [XmlInclude(typeof(T))] 静态声明。因此您可以将类型修改为如下:

// Include all possible types of Enum that might be serialized
[XmlInclude(typeof(Enummies.BigMethods))]
[XmlInclude(typeof(Enummies.SmallMethods))]
public class TESTCLASS
{
    private Enum _MethodType;

    // Surrogate object property for MethodObject required by XmlSerializer
    [XmlElement(Order = 1, ElementName = "MethodType")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public object MethodTypeObject
    {
        get { return MethodType; }
        set { MethodType = (Enum)value; }
    }

    // Ignore the Enum member that cannot be serialized directly
    [XmlIgnore]
    public Enum MethodType
    {
        get { return _MethodType; }
        set { _MethodType = value; }
    }
    public TESTCLASS() { }

    public TESTCLASS(Enummies.BigMethods bigM)
    {
        MethodType = bigM;
    }
    public TESTCLASS(Enummies.SmallMethods smallM)
    {
        MethodType = smallM;
    }
}

并且会生成如下的XML:

<TESTCLASS xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <MethodType xsi:type="BigMethods">BIG_THREE</MethodType>
</TESTCLASS>

或者

<?xml version="1.0" encoding="utf-16"?>
<TESTCLASS xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <MethodType xsi:type="SmallMethods">SMALL_TWO</MethodType>
</TESTCLASS>

注意到xsi:type 属性了吗?那是一个W3C standard attribute,一个元素可以使用它来显式地断言它的类型。 Microsoft 使用此属性来表示多态元素的类型信息,如 here 所述。

示例fiddle

您可能希望在MethodObject(而不是getter)的setter 中检查值类型是否是已知的Enum 类型,但这不是XML 序列化所必需的。

【讨论】:

  • 太棒了。我没有意识到只要在 XmlIncludes 中指定潜在类型,就可以序列化 System.Object 的成员。我想知道为什么我得到的异常与您看到的不同。另外,这些属性是必要的吗?我以前从未见过他们。 "[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]"
  • @TalenKylon - 这些属性不是必需的。它们阻止代理属性显示在调试器和属性编辑器中。我列出的例外是最内层属性而不是外层属性。另外,我在测试序列化之前添加了[XmlInclude(typeof(Enummies.BigMethods))] 属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 2016-02-05
  • 2013-09-15
相关资源
最近更新 更多