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 之间的区别,但实际应用程序使用了许多枚举。因此,该解决方案应允许使用多个枚举值。
好吧,不知道为什么会有这样的不同。但我有一个如下的解决方法:
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)
| 归档时间: |
|
| 查看次数: |
1358 次 |
| 最近记录: |