如何讓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