如何让 XmlSerializer 将布尔值编码为是/否?
Posted
技术标签:
【中文标题】如何让 XmlSerializer 将布尔值编码为是/否?【英文标题】:How can I get XmlSerializer to encode bools as yes/no? 【发布时间】:2010-10-12 02:59:32 【问题描述】:我正在将 xml 发送到另一个程序,该程序需要布尔标志为“是”或“否”,而不是“真”或“假”。
我有一个类定义如下:
[XmlRoot()]
public class Foo
public bool Bar get; set;
当我序列化它时,我的输出如下所示:
<Foo><Bar>true</Bar></Foo>
但我希望它是这样的:
<Foo><Bar>yes</Bar></Foo>
我可以在序列化时这样做吗?我宁愿不必诉诸于此:
[XmlRoot()]
public class Foo
[XmlIgnore()]
public bool Bar get; set;
[XmlElement("Bar")]
public string BarXml get return (Bar) ? "yes" : "no";
请注意,我还希望能够再次反序列化此数据。
【问题讨论】:
【参考方案1】:好的,我一直在研究这个。这是我想出的:
// use this instead of a bool, and it will serialize to "yes" or "no"
// minimal example, not very robust
public struct YesNo : IXmlSerializable
// we're just wrapping a bool
private bool Value;
// allow implicit casts to/from bool
public static implicit operator bool(YesNo yn)
return yn.Value;
public static implicit operator YesNo(bool b)
return new YesNo() Value = b;
// implement IXmlSerializable
public XmlSchema GetSchema() return null;
public void ReadXml(XmlReader reader)
Value = (reader.ReadElementContentAsString() == "yes");
public void WriteXml(XmlWriter writer)
writer.WriteString((Value) ? "yes" : "no");
然后我将我的 Foo 类更改为:
[XmlRoot()]
public class Foo
public YesNo Bar get; set;
请注意,因为 YesNo
可以隐式转换为 bool
(反之亦然),您仍然可以这样做:
Foo foo = new Foo() Bar = true; ;
if ( foo.Bar )
// ... etc
换句话说,您可以将其视为布尔值。
还有w00t!它序列化为:
<Foo><Bar>yes</Bar></Foo>
它还可以正确反序列化。
可能有某种方法可以让我的 XmlSerializer 自动将它遇到的任何 bool
s 转换为 YesNo
s - 但我还没有找到它。有人吗?
【讨论】:
可爱,正是我想要的。谢谢。 你也可以这样做:public enum BoolEnum [XmlEnum("no")] False = 0, [XmlEnum("yes")] True = 1 绝妙的解决方案! ?【参考方案2】:@Blorgbeard: 如果您在对象类中有多个 YesNo 类中的一个, 确保阅读整个元素。
public void ReadXml(XmlReader reader)
string element = reader.ReadOuterXml();
int startIndex = element.IndexOf('>') + 1;
int length = element.LastIndexOf('<') - startIndex;
string text = (element.Substring(startIndex, length).ToLowerInvariant();
Value = (text == "yes");
否则这可能会导致问题。
ReadXml 方法必须使用 WriteXml 方法写入的信息重构您的对象。
调用此方法时,读取器位于包装您的类型信息的元素的开头。也就是说,只是 在表示序列化开始的开始标记之前 目的。当这个方法返回时,它必须已经读取了整个元素 从头到尾,包括其所有内容。不像 WriteXml 方法,框架不处理包装元素 自动地。您的实施必须这样做。未能观察 这些定位规则可能会导致代码生成意外的运行时 异常或损坏的数据。
【讨论】:
【参考方案3】:我使用属性方法,但不是检查字符串是否等于是或否,我更喜欢检查字符串是否以(不区分大小写)“YT1”开头。这允许文件包含 true、True、t、T、y、Y、yes、Yes、1 等,所有这些都将评估为 true。虽然我可以指定 false 为 false、False、f、F、n、N、no、No、0 等,但任何与 true 不匹配的内容仍会评估为 false。
【讨论】:
【参考方案4】:非常简单。使用代理属性。对实际属性应用 XmlIgnore。代理项是一个字符串,并且必须使用采用元素名称覆盖的 XmlElement 属性。在覆盖中指定实际属性的名称。代理属性根据实际属性的值进行不同的序列化。您还必须为代理提供一个 setter,并且 setter 应该为它序列化的任何值适当地设置实际属性。换句话说,它需要双向。
截图:
public class SomeType
[XmlElement]
public int IntValue;
[XmlIgnore]
public bool Value;
[XmlElement("Value")]
public string Value_Surrogate
get return (Value)? "Yes, definitely!":"Absolutely NOT!";
set Value= (value=="Yes, definitely!");
点击这里查看full compilable source example。
【讨论】:
是的,但这是我在问题中给出的示例。我想知道是否有 更好的 方法:)【参考方案5】:将 bool 值序列化为“yes”或“no”会完全改变数据类型而不是 boolean。相反,您是否可以添加一个单独的属性来评估布尔值并根据其数据类型返回“是”或“否”?也许您甚至可以通过将返回类型设置为仅指定这些值的枚举来强制“是”或“否”。
public YesOrNo DoYouLoveIt
get return boolToEvaluate ? YesOrNo.Yes : YesOrNo.No;
这可能有点矫枉过正,但可能会满足您的需求。我为这样一个简单的值提出一个枚举的唯一原因是你会限制值而不是允许任何字符串。
【讨论】:
哇...是“是”太简单了还是什么? 哈哈 - 我知道。这是允许任何旧字符串使用字符串数据类型,或将其限制为特定值的问题。 另外,我刚刚意识到我听起来像个彻头彻尾的家伙:'( 没问题 - 我没有那样做 :)。 布尔值已经序列化为字符串——它们恰好是“真”和“假”,而不是“是”和“否”。我真的想用尽可能少的工作来做到这一点在要序列化的实际类中,因为有很多这样的类..【参考方案6】:您的属性示例可能是您可以做到的最简单的方法。如果有帮助,我相信您不需要将其设为公共属性,因为该属性在您背后的类上实现 ISerializable。要启用反序列化,您应该只需要实现set Bar = value == "yes";
【讨论】:
【参考方案7】:您需要做的更像是显示问题。如果您的应用程序允许,最好将数据类型保留为布尔值并在用户界面中显示是/否。
【讨论】:
“我正在将 xml 发送到另一个程序”听起来他无法控制“其他”程序。以上是关于如何让 XmlSerializer 将布尔值编码为是/否?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 .NET XmlSerializer 使值类型可以为空?
如何使 System.Web XmlSerializer 序列化程序编码引号 c#
如何让 MySQL 命令行工具默认显示存储为 BIT 的布尔值
R语言dplyr包的mutate函数将列添加到dataframe中或者修改现有的数据列:基于条件判断创建布尔型指示变量将异常离散编码转化为NA值