會有這個文章主要是因為,有需要比對序列化後字串是否符合預期的情境,但是卻因為沒有注意到這點讓測試程式碼怎樣都過不了 Orz
這個問題坦白說,若沒有踩到還真不會特別去計較這件事。關於 BOM(位元組順序記號),就我的實務經驗來講是很少會使用到的資訊,尤其是最常用到的編碼方式為 UTF-8,一般來說我不會馬上想到這個方向。
而 UTF-8 with BOM 的檔案基本上跟 without BOM 用肉眼是看不出差異的,只會在使用游標左右移動時發現需要多按一下才會動,在精神不濟時會以為這些都是幻覺 XD。但若是用 Notepad++ 的話,可以開啟 16 進位的檢視,就能看到 UTF-8 BOM 的那該死的位元組「ef bb bf」,在 windows 平台上有時可以看到存檔時可以選擇是否要包含 BOM 這個選項。
在 XmlTextWriter 實體要 new 出來時會有幾種作法,其中我們要講的就是把 Encoding 方式傳入的那種。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public class SerializeHelper
{
/// <summary>
/// 序列化物件編碼
/// 序列化後文字
/// </summary>
public string Serialize(object o, Encoding encoding)
{
XmlSerializer xmls = new XmlSerializer(o.GetType());
var xns = new XmlSerializerNamespaces();
xns.Add(string.Empty, string.Empty);
using (MemoryStream ms = new MemoryStream())
{
using (var writer = new XmlTextWriter(ms, encoding))
{
xmls.Serialize(writer, o, xns);
}
string xml = Encoding.UTF8.GetString(ms.ToArray());
return xml;
}
}
}
|
文字是否有加入 BOM 一般來說很難用肉眼看出來有什麼差異,因此我們使用 GetByteCount 來識別是否有 BOM 參入其中,看看是否真的多了那三個該死的位元標記符號。
在驗證的程式碼我們這樣寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| class Program
{
static void Main(string[] args)
{
var demonItem = new DemonClass()
{
Address = "Taipei",
Id = 1,
Name = "Ben",
Refer = new DemonClass()
};
var serialize = new SerializeHelper();
//// Encoding.UTF8預設會帶BOM
var stringObj = serialize.Serialize(demonItem, Encoding.UTF8);
Console.WriteLine("stringObj:" + Encoding.UTF8.GetByteCount(stringObj));
var stringObj2 = serialize.Serialize(demonItem, new UTF8Encoding(false));
Console.WriteLine("stringObj2:" + Encoding.UTF8.GetByteCount(stringObj2));
}
}
|
執行過後就會發現,我們在 .NET 平台最常使用到的呼叫方式就是那種會帶入 BOM 的那種。這點我們可以從原始碼中略窺一二
1
2
3
4
5
6
7
8
9
10
11
12
| public static Encoding UTF8
{
[__DynamicallyInvokable]
get
{
if (Encoding.utf8Encoding == null)
{
Encoding.utf8Encoding = new UTF8Encoding(true);
}
return Encoding.utf8Encoding;
}
}
|
而在 MSDN 中 UTF8Encoding 的建構子資訊中提到這個參數會影響到 GetPreamble 這個方法的行為。
在實測之中這個參數不只會影響 GetPreamble 這個方法的回傳值,也會影響到輸出的文字是否會含有 BOM。
會寫這篇主要是這個問題說大不大,但若踩到的話也可以吃足苦頭,寫下來避免下次遇到時問題找個老半天,才發現是這個編碼問題。
2017.03.30補充:
關於 UTF-8 編碼的檔案是否要帶BOM的問題,在 stackoverflow 的這篇討論串還不錯~