如何让XmlSerializer将bool编码为是/否?

[英]How can I get XmlSerializer to encode bools as yes/no?


I'm sending xml to another program, which expects boolean flags as "yes" or "no", rather than "true" or "false".

我将xml发送到另一个程序,它希望布尔标志为“是”或“否”,而不是“真”或“假”。

I have a class defined like:

我有一个类定义如下:

[XmlRoot()]
public class Foo {
    public bool Bar { get; set; }
}

When I serialize it, my output looks like this:

当我序列化它时,我的输出如下所示:

<Foo><Bar>true</Bar></Foo>

But I would like it to be this:

但我希望它是这样的:

<Foo><Bar>yes</Bar></Foo>

Can I do this at the time of serialization? I would prefer not to have to resort to this:

我可以在序列化时这样做吗?我宁愿不必诉诸于此:

[XmlRoot()]
public class Foo {
    [XmlIgnore()]
    public bool Bar { get; set; }

    [XmlElement("Bar")]
    public string BarXml { get { return (Bar) ? "yes" : "no"; } }
}

Note that I also want to be able to deserialize this data back again.

请注意,我还希望能够再次反序列化此数据。

8 个解决方案

#1


Ok, I've been looking into this some more. Here's what I've come up with:

好的,我一直在研究这个问题。这就是我提出的:

// 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");
    }
}

Then I change my Foo class to this:

然后我将我的Foo类更改为:

[XmlRoot()]
public class Foo {      
    public YesNo Bar { get; set; }
}

Note that because YesNo is implicitly castable to bool (and vice versa), you can still do this:

请注意,因为YesNo可以隐式地转换为bool(反之亦然),所以你仍然可以这样做:

Foo foo = new Foo() { Bar = true; };
if ( foo.Bar ) {
   // ... etc

In other words, you can treat it like a bool.

换句话说,你可以像对待bool一样对待它。

And w00t! It serializes to this:

而且!它序列化为:

<Foo><Bar>yes</Bar></Foo>

It also deserializes correctly.

它也正确地反序列化。

There is probably some way to get my XmlSerializer to automatically cast any bools it encounters to YesNos as it goes - but I haven't found it yet. Anyone?

可能有一些方法可以让我的XmlSerializer自动将遇到的任何bool转换为YesNos,但我还没有找到它。任何人?

#2


Very simple. Use a surrogate property. Apply XmlIgnore on the actual property. The surrogate is a string, and must use the XmlElement attribute that takes a element-name override. Specify the name of the actual property in the override. The surrogate property serializes differently based on the value of the actual property. You must also provide a setter for the Surrogate, and the setter should set the actual property appropriately, for whatever value it serialized. In other words it needs to go both ways.

非常简单。使用代理财产。在实际属性上应用XmlIgnore。代理是一个字符串,必须使用带有元素名称覆盖的XmlElement属性。在覆盖中指定实际属性的名称。代理属性根据实际属性的值进行不同的序列化。您还必须为Surrogate提供一个setter,并且setter应该适当地设置实际属性,无论它序列化什么值。换句话说,它需要双向进行。

Snip:

    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!"); }
        }

    }

click here for full compilable source example.

单击此处获取完整的可编译源示例。

#3


Making a bool value serialize as "yes" or "no" changes the data type from being a boolean at all. Instead, can you add a separate property which evaluates a boolean and returns "yes" or "no" as appropriate for it's data type? Maybe you could even force "yes" or "no" by making the return type be an enum which only specifies those values.

将bool值序列化为“yes”或“no”会将数据类型更改为布尔值。相反,你可以添加一个单独的属性来评估一个布尔值,并根据它的数据类型返回“是”或“否”吗?也许您甚至可以通过使返回类型为仅指定这些值的枚举来强制“是”或“否”。

public YesOrNo DoYouLoveIt
{
    get { return boolToEvaluate ? YesOrNo.Yes : YesOrNo.No; }
}

That might be overkill, but might answer your need. The only reason I bring up an enum for such a simple value is you'd be restricting the values vs. allowing any string.

这可能有点矫枉过正,但可能会满足您的需求。我为这样一个简单的值提出枚举的唯一原因是你要限制值而不是允许任何字符串。

#4


I use the property method, but instead of checking to see if the string is equal to yes or no, I prefer to check if the string starts with (case insensitive) "YT1". This allows the file to contain true, True, t, T, y, Y, yes, Yes, 1, etc. all which will evaluate to true. While I can specify that false is false, False, f, F, n, N, no, No, 0, etc., anything that doesn't match the true still evaluates to false.

我使用属性方法,但不是检查字符串是否等于是,我更喜欢检查字符串是否以(不区分大小写)“YT1”开头。这允许文件包含true,True,t,T,y,Y,yes,Yes,1等所有将评估为true的文件。虽然我可以指定false为false,False,f,F,n,N,no,No,0等,但任何与true不匹配的值仍为false。

#5


Your property example is probably the simplest way you could do it. If it helps, I believe you don't need to make it a public property, since the attribute implements ISerializable on the class behind your back. To enable deserialization, you should be able to just implement set { Bar = value == "yes"; }

您的属性示例可能是您可以执行此操作的最简单方法。如果它有帮助,我相信你不需要把它变成公共属性,因为该属性在你背后的类上实现了ISerializable。要启用反序列化,您应该能够实现set {Bar = value ==“yes”; }

#6


what about implementing OnSerializing and OnDeserializing methods?

那么实现OnSerializing和OnDeserializing方法呢?

#7


What you're needing to do sounds more like a display issue. If your application allows, you will be better off keeping the data type as a boolean and displaying Yes/No in your user interface.

您需要做的事情听起来更像是显示问题。如果您的应用程序允许,最好将数据类型保留为布尔值,并在用户界面中显示“是/否”。

#8


@Blorgbeard: If you have more then one of these YesNo classes in an object class, make sure to read the entire element.

@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");
}

Otherwise this might cause problems.

否则这可能会导致问题。

The ReadXml method must reconstitute your object using the information that was written by the WriteXml method.

ReadXml方法必须使用WriteXml方法写入的信息重新构建对象。

When this method is called, the reader is positioned at the start of the element that wraps the information for your type. That is, just before the start tag that indicates the beginning of a serialized object. When this method returns, it must have read the entire element from beginning to end, including all of its contents. Unlike the WriteXml method, the framework does not handle the wrapper element automatically. Your implementation must do so. Failing to observe these positioning rules may cause code to generate unexpected runtime exceptions or corrupt data.

调用此方法时,读取器位于包含类型信息的元素的开头。也就是说,就在指示序列化对象开始的开始标记之前。当此方法返回时,它必须从头到尾读取整个元素,包括其所有内容。与WriteXml方法不同,框架不会自动处理包装元素。您的实施必须这样做。如果不遵守这些定位规则,可能会导致代码生成意外的运行时异常或损坏的数据。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2009/03/09/1927116b712c5394e175e5aa68fe0c2e.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com