当前位置:  开发笔记 > 编程语言 > 正文

LINQ性能影响

如何解决《LINQ性能影响》经验,为你挑选了1个好方法。

我有一个简单的过程来删除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 被转换为char [].我似乎用LINQ做了很多 - 在数组和枚举之间进行了更改.

我应该关注这件事吗?一般来说,当一个明确的替代方案可能更加冗长时,依赖于LINQ扩展方法,我将获得什么样的性能影响.

也许这是一个过于宽泛的问题.



1> Jon Skeet..:

好吧,你不需要第一次调用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,
                                           IEnumerable sequence)
{
    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,
                                        Func predicate)
{
    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结束,只需返回原始字符串.

推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有