为什么 XmlSerializer 无法在 .Net Core 中序列化枚举值,但在 .NET Framework 中工作正常

Vic*_*aru 9 c# xml-serialization xmlserializer .net-core

概括

.NET Core 应用程序无法 XML 序列化包含枚举值的对象,而 .NET Framework (4.7.2) 成功。这是一个已知的重大更改,如果是,我该如何解决?

代码示例

以下控制台应用程序不会在 .NET Framework 4.7.2 项目中引发异常:

public enum MyEnum
{
    One,
}

public class ValueContainer
{
    public object Value;
}
class Program
{
    static void Main(string[] args)
    {
        XmlSerializer newSerializer = XmlSerializer.FromTypes(
            new[] { typeof(ValueContainer)})[0];

        var instance = new ValueContainer();
        instance.Value = MyEnum.One;

        using (var memoryStream = new MemoryStream())
        {
            newSerializer.Serialize(memoryStream, instance);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

.NET Core 3.0 控制台应用程序中完全相同的代码在调用时抛出以下异常Serialize

System.InvalidOperationException
  HResult=0x80131509
  Message=There was an error generating the XML document.
  Source=System.Private.Xml
  StackTrace:
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o, XmlSerializerNamespaces namespaces)
   at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o)
   at CoreXml.Program.Main(String[] args) in C:\Users\vchel\source\repos\CoreXml\CoreXml\Program.cs:line 28

Inner Exception 1:
InvalidOperationException: The type CoreXml.MyEnum may not be used in this context.
Run Code Online (Sandbox Code Playgroud)

我的代码做错了吗?这是 .NET Framework 和 .NET Core 之间的重大变化吗?

有解决方法吗?

更新

我应该指出,在 .NET 4.7.2 中序列化时,我得到以下(所需的)Value 输出:

 <Value xsi:type="xsd:int">0</Value>
Run Code Online (Sandbox Code Playgroud)

我希望为 .NET Core 提出的任何解决方案也输出相同的 XML,因为我需要保持与现有文件和不使用 .NET Standard 的旧版本应用程序的兼容性。

更新 2

我应该在原始问题中包含此信息,但是现在我正在尝试实施答案,我发现有些要求我一开始没有想到。

首先,被序列化的对象也在逻辑中使用,逻辑依赖于存储在值中的对象是一个枚举。因此,将值永久转换为整数(例如通过在 setter 中进行转换)将影响应用程序的逻辑,因此我无法做到这一点。

其次,尽管我的示例已被简化以显示 .NET Framework 和 .NET Core 之间的区别,但实际应用程序使用了许多枚举。因此,该解决方案应允许使用多个枚举值。

Eld*_*dar 1

好吧,不知道为什么会有这样的不同。但我有一个如下的解决方法:


public enum MyEnum
{        
   One,
}

public class ValueContainer
    {
        [XmlIgnore]
        private object _value;

        public object Value
        {
            get
            {
                return _value;
            }
            set
            {
                var type = value.GetType();
                _value = type.IsEnum ? (int)value : value;
            }
        }
    }

class Program
{
   static void Main(string[] args)
   {
      var newSerializer = XmlSerializer.FromTypes(
           new[] { typeof(ValueContainer))[0];
           var instance = new ValueContainer();
           instance.Value = MyEnum.One;
           var memoryStream = new MemoryStream();
           newSerializer.Serialize(memoryStream, instance);
           var str = Encoding.Default.GetString(memoryStream.ToArray());
     }
}
Run Code Online (Sandbox Code Playgroud)

输出

<?xml version="1.0"?>
<ValueContainer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Value xsi:type="xsd:int">0</Value>
</ValueContainer>
Run Code Online (Sandbox Code Playgroud)

编辑:我没有注意到序列化的值,因为<Value>One</Value>这个工作比以前更脏,但它有效。

小提琴

编辑2:正如@Victor Chelaru 在评论中提到的,我决定保留这两种解决方法,但必须声明它们都有相同的缺点,即丢失带有序列化xml 输出的枚举的类型信息。

[XmlType(typeName: "int",Namespace="http://www.w3.org/2001/XMLSchema")]
public enum MyEnum : int
{
    [XmlEnum("0")]
    One,
}

public class ValueContainer
{
    public object Value;
}

public static void Main()
{
    var newSerializer = XmlSerializer.FromTypes(new[]{typeof(ValueContainer), typeof(MyEnum)})[0];
    var instance = new ValueContainer();
    instance.Value = MyEnum.One;
    var memoryStream = new MemoryStream();
    newSerializer.Serialize(memoryStream, instance);
    var str = Encoding.Default.GetString(memoryStream.ToArray());
    str.Dump();
}
Run Code Online (Sandbox Code Playgroud)

小提琴

编辑3:正如@Simon Mourier在上面的评论中提到的,解决方法可以在不直接修改枚举的情况下实现,使用XmlAttributeOverrides如下:

[XmlType(typeName: "int")]
public enum MyEnum : int
{       
    One,
}

public class ValueContainer
{
    public object Value;
}

public static void Main()
{               
    var ov = new XmlAttributeOverrides(); 
    ov.Add(typeof(MyEnum), nameof(MyEnum.One), new XmlAttributes { XmlEnum = new XmlEnumAttribute("0") }); 
    var newSerializer = new XmlSerializer(typeof(ValueContainer), ov, new[] { typeof(MyEnum) }, null, null);
    var instance = new ValueContainer();
    instance.Value = MyEnum.One;
    var memoryStream = new MemoryStream();
    newSerializer.Serialize(memoryStream, instance);
    var str = Encoding.Default.GetString(memoryStream.ToArray());
    str.Dump();
}
Run Code Online (Sandbox Code Playgroud)

小提琴