博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
由一个Xml序列化操作看mscorlib.dll 2.0、4.0 String的Trim方法实现
阅读量:6948 次
发布时间:2019-06-27

本文共 2804 字,大约阅读时间需要 9 分钟。

有一段Xml序列化的代码,基于2.0 Runtime传递到Server转换正常。当客户端在4.0 Runtime下调用,Server返回格式错误。序列化代码如下:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));using (MemoryStream memoryStream = new MemoryStream()){    XmlTextWriter xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);    xmlSerializer.Serialize(xmlWriter, graph, ns);    return Encoding.UTF8.GetString(memoryStream.ToArray()).Trim();}

用Microsoft Network Monitor监视4.0 Runtime下发送的数据内容,转换后的Xml头部多出了3个字节:EF(239) BB(187) BF(191),它是UTF-8的preamble(encoding bites),字符值为65279。.NET Framework 2.0 String的Trim函数内部会去除一组预定义的空白字符集,其中就包括了65279。反编译代码如下(最后一个字符'\ufeff'是62579的16进制表示):

public string Trim(){    return this.TrimHelper(string.WhitespaceChars, 2);}
internal static readonly char[] WhitespaceChars = new char[25]{    '\t',    '\n',    '\v',    '\f',    '\r',    ' ',    '\u0085',    '\u00a0',    '\u1680',    '\u2000',    '\u2001',    '\u2002',    '\u2003',    '\u2004',    '\u2005',    '\u2006',    '\u2007',    '\u2008',    '\u2009',    '\u200a',    '\u200b',    '\u2028',    '\u2029',    '\u3000',    '\ufeff'};

.NET Framework 4.0 String的Trim函数,反编译代码如下:

public string Trim(){    return this.TrimHelper(2);}

4.0版本String的Trim函数内部不再去除一组预定义的空白字符集,直接导致了之前Xml序列化无法去除UTF-8编码后的preamble。解决方法就是根据不同字符编码尝试去除转换后的preamble。代码如下:

public static string TrimPreamble(this string value, Encoding encoding){    if (String.IsNullOrEmpty(value))    {        return value;    }    var encodingString = encoding.GetString(encoding.GetPreamble());    if (value.Length <= encodingString.Length)    {        return value;    }    for (var i = 0; i < encodingString.Length; ++i)    {        if (value[i] != encodingString[i])        {            return value;        }    }    return value.Remove(0, encodingString.Length);}

在我的实现版本并没有使用StartWith或IndexOf函数是有原因的,比如上面的函数可以简写成:

public static string TrimPreamble(this string value, Encoding encoding){    if (String.IsNullOrEmpty(value))    {        return value;    }    var encodingString = encoding.GetString(encoding.GetPreamble());    if (value.StartsWith(encodingString))    {        value = value.Remove(0, encodingString.Length);    }    return value;}

当客户端基于.NET Framework 2.0,发送字符串到基于.NET Framework 4.0运行的Server,preamble的偏移在实际字符的-1位。StartWith、IndexOf函数的匹配并不是针对String实际可见的char array逐一匹配,由.NET平台决定字符串在内存的存储方式,它们会返回字符已存在,但并不存在于可见的char array中。具体原因可以查看System.Globalization.CompareInfo.InternalFindNLSStringEx函数。

不使用XmlTextWriter可以避免encoding bites,比如:StringWriter。其缺点是无法指定Encoding,但可以继承StringWriter并重新定义它的构造函数。

public sealed class EncodingStringWriter : StringWriter{    private Encoding _encoding;    public EncodingStringWriter(StringBuilder sb, Encoding encoding)        : base(sb)    {        _encoding = encoding;    }    public override Encoding Encoding    {        get        {            return _encoding;        }    }}

 

转载地址:http://gshnl.baihongyu.com/

你可能感兴趣的文章
Python基础11_函数名运用,闭包,迭代器
查看>>
java集合框架
查看>>
python之configparse模块
查看>>
CentOS6.2编译安装MySQL5.5.25
查看>>
Nyoj 星际之门(一)(Cayley定理)
查看>>
词法分析程序
查看>>
前端基础之css
查看>>
网址收藏
查看>>
人的成长,注定是一场孤独的旅途 ...(360doc)
查看>>
死锁排查的小窍门 --使用jdk自带管理工具jstack
查看>>
安卓开发者必备的42个链接
查看>>
DeadLine
查看>>
2018-2019 Exp2 后门原理与实践
查看>>
bzoj5137 [Usaco2017 Dec]Standing Out from the Herd
查看>>
Mysql压缩包版zip的安装方法
查看>>
UWP 动画
查看>>
浅析设计模式(二)——工厂方法模式
查看>>
面试宝典-面试题1
查看>>
DAY1 linux 50条命令
查看>>
Eclipse设置Tab键为四个空格
查看>>