我有一个简单的过程来删除XML中非法的所有字符串:
string SanitizeXml(string xml) { return string.Concat (xml.ToCharArray().Where(c => IsLegalXmlChar(c)).ToArray()); }
这很好,很简洁.但我很担心它的表现.使用简单的for循环可以轻松完成同样的事情:
string SanitizeXml(string xml) { var buffer = new StringBuilder(); foreach(char c in xml) { if (IsLegalXmlChar(c)) { buffer.Append(c); } } return buffer.ToString(); }
在我看来,在第二个例子中,xml被转换为char [],而Where()的IEnumerable
我应该关注这件事吗?一般来说,当一个明确的替代方案可能更加冗长时,依赖于LINQ扩展方法,我将获得什么样的性能影响.
也许这是一个过于宽泛的问题.
好吧,你不需要第一次调用ToCharArray()
- 字符串实现IEnumerable
.但是,我同意在这种情况下StringBuilder和循环可能更合适.
我不确定是什么string.Concat(char [])随便做什么,顺便说一句 - 你为什么不只是使用带有char数组的字符串构造函数?换句话说,经过这些修改:
static string SanitizeXml(string xml) { return new string (xml.Where(c => IsLegalXmlChar(c)).ToArray()); }
我仍然更喜欢StringBuilder解决方案,但通过提供适当的容量来开始,可以针对常见情况(非常少的非法字符)进行改进:
string SanitizeXml(string xml) { var buffer = new StringBuilder(xml.Length); foreach(char c in xml) { if (IsLegalXmlChar(c)) { buffer.Append(c); } } return buffer.ToString(); }
我之前没有想到的一个替代方案可能是StringBuilder上的扩展方法:
// Can't just call it Append as otherwise StringBuilder.Append(object) would // be used :( public static StringBuilder AppendSequence(this StringBuilder builder, IEnumerablesequence) { foreach (char c in sequence) { builder.Append(c); } return builder; }
然后你可以像这样使用它:
xml = new StringBuilder(xml.Length) .AppendSequence(xml.Where(IsLegalXmlChar) .ToString();
(如果你愿意的话,你可以让AppendSequence有其他重载来获取IEnumerable等.)
编辑:另一种选择可能是避免经常调用Append,而是使用附加子字符串的重载.然后你可以再次为StringBuilder构建一个扩展方法,类似于(完全没有测试,我很害怕 - 我甚至没有尝试编译它):
public static StringBuilder AppendWhere(this StringBuilder builder, string text, Funcpredicate) { int start = 0; bool lastResult = false; for (int i=0; i < text.Length; i++) { if (predicate(text[i])) { if (!lastResult) { start = i; lastResult = true; } } else { if (lastResult) { builder.Append(text, start, i-start); lastResult = false; } } } if (lastResult) { builder.Append(text, start, text.Length-start); } return builder; }
用法示例:
xml = new StringBuilder(xml.Length).AppendWhere(xml, IsLegalXmlChar) .ToString();
另一种方法是将它更改为String上的扩展方法,懒惰地创建StringBuilder,如果你以start = 0结束,只需返回原始字符串.