确定字符串长度是否最有效的方法!= 0?

时间:2010-08-02 17:22:32

标签: c# string content-length

我正在努力加快以下步伐:

string s; //--> s is never null

if (s.Length != 0)
{
   <do something>
}

问题是,看起来.Length实际上是对字符串中的字符进行计数,这比我需要的工作更多。有人知道如何加快这个速度吗?

或者,有没有办法确定s [0]是否存在,w / out检查字符串的其余部分?

9 个答案:

答案 0 :(得分:23)

编辑:现在您已经提供了更多背景信息:

  • 试图重现这一点,我根本没有找到string.Length的瓶颈。使其更快的唯一方法是注释掉测试和if块的主体 - 这不是很公平。只是注释掉条件会减慢速度,即无条件地复制参考文件比检查条件要慢。

  • 正如已经指出的那样,使用为您删除空条目的string.Split重载是真正的杀手优化。

  • 您可以通过避免每次只创建一个空格来创建一个新的char数组。你总是会有效地传递同样的东西,为什么不利用它?

  • 空数组实际上是不可变的。您可以通过始终返回相同的内容来优化null / empty案例。

优化的代码变为:

private static readonly char[] Delimiters = " ".ToCharArray();
private static readonly string[] EmptyArray = new string[0];

public static string[] SplitOnMultiSpaces(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        return EmptyArray;
    }

    return text.Split(Delimiters, StringSplitOptions.RemoveEmptyEntries);
}

String.Length绝对计算字符串中的字母数。该值存储为一个字段 - 尽管我似乎记得该字段的最高位用于记住所有字符是否都是ASCII(或者过去常常用于启用其他优化)。所以属性访问可能需要做一个位掩码,但它仍然是O(1)并且我希望JIT也可以内联它。 (它实现为extern,但希望在这种情况下不会影响JIT - 我怀疑这是一个足够普遍的操作,可能有特殊的支持。)

如果您已经知道该字符串不为null,那么您现有的

测试
if (s.Length != 0)
如果您正在寻找原始性能IMO,那么

是最好的方法。在大多数情况下,我个人写道:

if (s != "")

更清楚地表明,我们对作为一个值的长度并不是那么感兴趣,因为这是否是空字符串。这将比长度测试略慢,但我相信它更清晰。与以往一样,我会选择最清晰的代码,直到你有基准/分析数据来表明这真的 是一个瓶颈。我知道你的问题明确是关于找到最有效的测试,但我想我还是会提到这个。您是否有证据证明此 是瓶颈?

编辑:只是为了更清楚地说明我的使用string.IsNullOrEmpty的建议:对该方法的调用告诉我,调用者明确地试图处理的情况是变量为null,否则他们不会提到它。如果在代码的这一点上,如果变量 为null,则它将被视为错误,那么您不应该尝试将其作为正常情况处理。

在这种情况下,Length检查实际上是更好,而不是我建议的不等式测试:它充当隐式断言,即变量不为空。如果你有一个bug并且 为null,那么测试将抛出一个异常,并且会及早发现bug。如果使用相等性测试,它会将null视为与空字符串不同,因此它将进入“if”语句的主体。如果你使用string.IsNullOrEmpty,它会将null视为与空相同,因此它不会进入该块。

答案 1 :(得分:9)

String.IsNullOrEmpty是检查null或零长度字符串的首选方法。

在内部,它将使用长度。不应该动态计算字符串的Length属性。

如果您完全确定该字符串永远不会为null并且您对String.IsNullOrEmpty有强烈的反对意见,那么我能想到的最有效的代码是:

if(s.Length > 0)
{
    // Do Something
}

或者,甚至可能更好:

if(s != "")
{
    // Do Something
}

答案 2 :(得分:5)

访问Length属性不应该计算 - .NET字符串在对象内存储计数。

SSCLI/Rotor source code包含一条有趣的评论,表明String.Length是(a)有效的,(b)魔术:

// Gets the length of this string
//
/// This is a EE implemented function so that the JIT can recognise is specially
/// and eliminate checks on character fetchs in a loop like:
/// for(int I = 0; I < str.Length; i++) str[i]
/// The actually code generated for this will be one instruction and will be inlined.
//
public extern int Length {
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    get;
}

答案 3 :(得分:3)

这是函数String.IsNullOrEmpty -

if (!String.IsNullOrEmpty(yourstring))
{
  // your code
}

答案 4 :(得分:1)

根据您在答案中描述的意图,为什么不尝试在Split上使用此内置选项:

s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);

答案 5 :(得分:0)

与性能一样:基准。
使用C#3.5或之前,您需要测试yourString.Length vs String.IsNullOrEmpty(yourString)

使用C#4,执行上述两项操作并添加String.IsNullOrWhiteSpace(yourString)

当然,如果您知道您的字符串永远不会为空,您可以尝试访问s[0]并在不存在时处理异常。这不是通常的良好做法,但它可能更接近您的需要(如果s应始终具有非空白值)。

答案 6 :(得分:0)

        for (int i = 0; i < 100; i++)
        {
            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            string s = "dsfasdfsdafasd";

            timer.Start();
            if (s.Length > 0)
            {
            }

            timer.Stop();
            System.Diagnostics.Debug.Write(String.Format("s.Length != 0 {0} ticks       ", timer.ElapsedTicks));

            timer.Reset();
            timer.Start();
            if (s == String.Empty)
            {
            }

            timer.Stop();
            System.Diagnostics.Debug.WriteLine(String.Format("s== String.Empty {0} ticks", timer.ElapsedTicks));
        }

使用秒表,s.length!= 0需要更少的刻度,然后s == String.Empty

修复代码后

答案 7 :(得分:0)

只需使用String.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries)即可完成所有操作。

答案 8 :(得分:0)

 $usertypes=Usertype::find()->where(['<>',['user_type_id'=>['2,3,4']]])->all();

如果s为null或Empty,或者s仅由空格字符组成,则为true。

相关问题