可为空的对象必须具有一个值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可为空的对象必须具有一个值相关的知识,希望对你有一定的参考价值。
参考技术A 意思是,可为null的对象,初始化的时候,你得给一个值给他本回答被提问者采纳使用 XmlSerializer 将空 xml 属性值反序列化为可为空的 int 属性
【中文标题】使用 XmlSerializer 将空 xml 属性值反序列化为可为空的 int 属性【英文标题】:Deserializing empty xml attribute value into nullable int property using XmlSerializer 【发布时间】:2010-11-20 17:01:03 【问题描述】:我从第 3 方获得了一个 xml,我需要将其反序列化为 C# 对象。此 xml 可能包含值为整数类型或空值的属性:attr=”11” 或 attr=””。我想将此属性值反序列化为可空整数类型的属性。但 XmlSerializer 不支持反序列化为可空类型。以下测试代码在创建 XmlSerializer 期间失败并出现 InvalidOperationException "There was an error reflection type 'TestConsoleApplication.SerializeMe'.".
[XmlRoot("root")]
public class SerializeMe
[XmlElement("element")]
public Element Element get; set;
public class Element
[XmlAttribute("attr")]
public int? Value get; set;
class Program
static void Main(string[] args)
string xml = "<root><element attr=''>valE</element></root>";
var deserializer = new XmlSerializer(typeof(SerializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (SerializeMe)deserializer.Deserialize(xmlStream);
当我将“Value”属性的类型更改为 int 时,反序列化失败并出现 InvalidOperationException:
XML 文档 (1, 16) 中存在错误。
任何人都可以建议如何将具有空值的属性反序列化为可空类型(作为 null),同时将非空属性值反序列化为整数?有什么技巧可以让我不必手动对每个字段进行反序列化(实际上有很多)?
在 ahsteele 发表评论后更新:
Xsi:nil attribute
据我所知,此属性仅适用于 XmlElementAttribute - 此属性指定元素没有内容,无论是子元素还是正文。但我需要找到 XmlAttributeAttribute 的解决方案。无论如何,我无法更改 xml,因为我无法控制它。
bool *Specified property
此属性仅在属性值非空或缺少属性时有效。当 attr 具有空值 (attr='') 时,XmlSerializer 构造函数将失败(如预期的那样)。
public class Element
[XmlAttribute("attr")]
public int Value get; set;
[XmlIgnore]
public bool ValueSpecified;
Custom Nullable class like in this blog post by Alex Scordellis
我尝试采用这篇博文中的课程来解决我的问题:
[XmlAttribute("attr")]
public NullableInt Value get; set;
但 XmlSerializer 构造函数失败并出现 InvalidOperationException:
无法序列化 TestConsoleApplication.NullableInt 类型的成员“值”。
XmlAttribute/XmlText 不能用于编码实现 IXmlSerializable 的类型
丑陋的代理解决方案(我很惭愧我在这里写了这段代码:)):
public class Element
[XmlAttribute("attr")]
public string SetValue get; set;
public int? GetValue()
if ( string.IsNullOrEmpty(SetValue) || SetValue.Trim().Length <= 0 )
return null;
int result;
if (int.TryParse(SetValue, out result))
return result;
return null;
但我不想提出这样的解决方案,因为它破坏了我的类对其消费者的接口。我最好手动实现 IXmlSerializable 接口。
目前看来我必须为整个 Element 类(它很大)实现 IXmlSerializable 并且没有简单的解决方法......
【问题讨论】:
这个问题困扰了我十年。 2021年就没有简单的装饰器来解决这个问题了吗? 【参考方案1】:这应该可行:
[XmlIgnore]
public int? Age get; set;
[XmlElement("Age")]
public string AgeAsText
get return (Age.HasValue) ? Age.ToString() : null;
set Age = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?);
【讨论】:
这会起作用,但这与我的问题中的第 4 个解决方案相同。我不想将代理字段引入我班级的公共接口。谢谢 FWIW,我发现此解决方案比显式 IXmlSerializable 实现(已接受的解决方案)更好,尽管不是针对 OP 的具体问题。除非绝对需要,否则我会避免实施 IXmlSerializable,因为从长远来看,这最终会花费我更多的维护成本。在这种简单的情况下并且没有任何其他缓解因素,我将不加思索地选择“丑陋”的替代解决方案。 会产生一些额外的开销,但您当然可以有两个类 - 一个用于反序列化,具有所有这些额外属性,另一个仅具有实际值。创建一个隐式转换,它只返回一个正在转换的类的新实例以及所有正确的信息。【参考方案2】:我通过实现 IXmlSerializable 接口解决了这个问题。我没有找到更简单的方法。
这里是测试代码示例:
[XmlRoot("root")]
public class DeserializeMe
[XmlArray("elements"), XmlArrayItem("element")]
public List<Element> Element get; set;
public class Element : IXmlSerializable
public int? Value1 get; private set;
public float? Value2 get; private set;
public void ReadXml(XmlReader reader)
string attr1 = reader.GetAttribute("attr");
string attr2 = reader.GetAttribute("attr2");
reader.Read();
Value1 = ConvertToNullable<int>(attr1);
Value2 = ConvertToNullable<float>(attr2);
private static T? ConvertToNullable<T>(string inputValue) where T : struct
if ( string.IsNullOrEmpty(inputValue) || inputValue.Trim().Length == 0 )
return null;
try
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
return (T)conv.ConvertFrom(inputValue);
catch ( NotSupportedException )
// The conversion cannot be performed
return null;
public XmlSchema GetSchema() return null;
public void WriteXml(XmlWriter writer) throw new NotImplementedException();
class TestProgram
public static void Main(string[] args)
string xml = @"<root><elements><element attr='11' attr2='11.3'/><element attr='' attr2=''/></elements></root>";
XmlSerializer deserializer = new XmlSerializer(typeof(DeserializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (DeserializeMe)deserializer.Deserialize(xmlStream);
【讨论】:
【参考方案3】:我自己最近一直在搞乱序列化,发现以下文章和帖子在处理值类型的空数据时很有帮助。
How to make a value type nullable with XmlSerializer in C# - serialization 的答案详细介绍了 XmlSerializer 的一个非常漂亮的技巧。具体来说,XmlSerialier 会查找 XXXSpecified 布尔属性以确定是否应包含它,从而允许您忽略空值。
Alex Scordellis 提出了一个 *** 问题,收到了a good answer。 Alex 还在他的博客上写了一篇关于他试图解决的问题的精彩文章Using XmlSerializer to deserialize into a Nullable<int>。
Xsi:nil Attribute Binding Support 上的 MSDN 文档也很有用。正如IXmlSerializable Interface 上的文档一样,尽管编写自己的实现应该是你最后的手段。
【讨论】:
“使用 XmlSerializer 反序列化为 Nullable”链接已失效。 Here's a cached version from google @Anttu 我将答案中的链接切换到原始的 Wayback Machine 存档使用 XmlSerializer 反序列化为 Nullable我想我不妨把我的答案扔进帽子里: 通过创建实现 IXmlSerializable 接口的自定义类型解决了这个问题:
假设您有一个具有以下节点的 XML 对象:
<ItemOne>10</Item2>
<ItemTwo />
代表它们的对象:
public class MyItems
[XmlElement("ItemOne")]
public int ItemOne get; set;
[XmlElement("ItemTwo")]
public CustomNullable<int> ItemTwo get; set; // will throw exception if empty element and type is int
动态可空结构表示任何潜在的可空条目以及转换
public struct CustomNullable<T> : IXmlSerializable where T: struct
private T value;
private bool hasValue;
public bool HasValue
get return hasValue;
public T Value
get return value;
private CustomNullable(T value)
this.hasValue = true;
this.value = value;
public XmlSchema GetSchema()
return null;
public void ReadXml(XmlReader reader)
string strValue = reader.ReadString();
if (String.IsNullOrEmpty(strValue))
this.hasValue = false;
else
T convertedValue = strValue.To<T>();
this.value = convertedValue;
this.hasValue = true;
reader.ReadEndElement();
public void WriteXml(XmlWriter writer)
throw new NotImplementedException();
public static implicit operator CustomNullable<T>(T value)
return new CustomNullable<T>(value);
public static class ObjectExtensions
public static T To<T>(this object value)
Type t = typeof(T);
// Get the type that was made nullable.
Type valueType = Nullable.GetUnderlyingType(typeof(T));
if (valueType != null)
// Nullable type.
if (value == null)
// you may want to do something different here.
return default(T);
else
// Convert to the value type.
object result = Convert.ChangeType(value, valueType);
// Cast the value type to the nullable type.
return (T)result;
else
// Not nullable.
return (T)Convert.ChangeType(value, typeof(T));
【讨论】:
【参考方案5】:您也可以通过将xml
加载到XmlDocument
中然后将其反序列化为Json
来获取您正在寻找的对象T
。
public static T XmlToModel<T>(string xml)
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
T result = JsonConvert.DeserializeObject<T>(jsonText);
return result;
【讨论】:
从link复制并粘贴答案以上是关于可为空的对象必须具有一个值的主要内容,如果未能解决你的问题,请参考以下文章
使用 XmlSerializer 将空 xml 属性值反序列化为可为空的 int 属性