【问题标题】:PowerShell And StringBuilderPowerShell 和 StringBuilder
【发布时间】:2011-10-18 11:20:06
【问题描述】:

我是 PowerShell 新手,但熟悉 .NET 类。

我在 PowerShell 脚本中使用 System.Text.StringBuilder。脚本是这样的

Function MyStringFunc([String]$line) {
    $r = New-Object -TypeName "System.Collections.Generic.List``1[[System.String]]";
    $sb = New-Object -TypeName "System.Text.StringBuilder";

    foreach ($c in $line) {
        $sb.Append($c);
        $r.Add($sb.ToString());
    }

    return $r;
}

$line1 = "123";
$a = MyStringFunc $line1;
$a

我预计结果是

1
12
123

结果是

                  Capacity                MaxCapacity                    Length
                  --------                -----------                    ------
                        16                 2147483647                         3
123

我是不是做错了什么?

【问题讨论】:

    标签: .net powershell stringbuilder


    【解决方案1】:

    StringBuilder 上的几个方法,如 Append IIRC,返回 StringBuilder,以便您可以调用更多 StringBuilder 方法。然而 PowerShell 的工作方式是输出所有结果(在 .NET 方法调用的情况下返回值)。在这种情况下,将结果转换为 [void] 以忽略返回值,例如:

    [void]$sb.Append($c)
    

    请注意,您不需要在 PowerShell 中结束 ; 中的行。但是,如果您将多个命令放在同一行,则使用 ;' 分隔这些命令。

    【讨论】:

    • 谢谢它的工作。但是,此行为未在 MSDN 中注明。我能知道官方参考在哪里吗?
    • MSDN 正确指出 StringBuilder.Append(...) 返回 StringBuilder。在像 C# 这样的语言中,这不是问题,因为您可以忽略返回值。但是在 PowerShell 中,它隐式输出任何返回值。如果您不希望 PowerShell 输出返回值,必须将表达式转换为 [void](或通过管道将表达式转换为 Out-Null)。这只是 C# 和基于 shell 的脚本语言(如 PowerShell)之间的根本区别。
    【解决方案2】:

    因为您说您是 PowerShell 的新手。我的回答是关于你编写 PowerShell 的方式。

    PowerShell 是一种脚本语言,由非开发人员程序员(例如管理员)使用。你是一个拥有所有知识的 C# 开发人员,但你可以更简单地编写你想写的东西。在 PowerShell 中存在使用 Lists 和 Hastables 的语法,请尝试以下操作:

    $a = @()
    $a += "Bonjour"
    $a += "Salut"
    $a
    $a | get-member
    Get-Member -InputObject $a
    
    $rwc = @{}
    $rwc += @{1="Blues"}
    $rwc += @{2="Blacks"}
    $rwc
    $rwc | get-member
    Get-Member -InputObject $rwc
    

    这里有三个函数做同样的事情,我知道字符串生成器在内存中效率更高,但在这种情况下谁在乎呢。

    Function MyStringFunc([String]$line)
    { 
      $r = New-Object -TypeName "System.Collections.Generic.List``1[[System.String]]"; 
      $sb = New-Object -TypeName "System.Text.StringBuilder"; 
    
      foreach ($c in [Char[]]$line)
      { 
        $a = $sb.Append($c); 
        $r.Add($sb.ToString()); 
      }  
      return $r; 
    } 
    
    # A more simple way
    Function MoreReadableStringFunction([String]$line)
    {
      $r = @() # an untyped list
    
      foreach ($c in [Char[]]$line)
      { 
        $a += $c; 
        $r += $a;
      } 
      return $r;
    }
    
    # More simple but not so readable
    Function MoreSimpleStringFunction([String]$line)
    {
      $r = @() # an untyped list
    
      [Char[]]$line | % {$a += $_; $r += $a} 
      return $r;
    }
    
    
    Clear-Host
    $line1 = "123";
    
    $t1 = MyStringFunc $line1; 
    $t1
    
    $t2 = MoreReadableStringFunction $line1
    $t2
    
    $t3 = MoreSimpleStringFunction $line1
    $t3
    

    【讨论】:

    • 我不会说谁在乎使用 += 和 stringbuilder 在 powershell 中连接之间的区别......它的效率呈指数级降低,而在 stringbuilder 中可能需要 0.2 秒来做同样的事情+= 需要 60 秒才能完成。即使有适量的+=,这也是一个非常非常大的差异。使用 += 10000 行循环的测量命令:TotalSeconds:49.0461414 秒 - 与 stringbuilder 相同的循环:TotalSeconds:使用测量命令测量的 0.2216707 秒
    【解决方案3】:
    1. foreach 不会遍历字符串中的字符,而是将其视为单个项目。所以我们必须将字符串转换为[char[]](或使用$line.GetEnumerator())。

    2. 表达式$sb.Append($c) 获取构建器实例。在 PowerShell 中,它被写入输出。只要它是不需要的,我们应该抑制这个输出($null = ...... > $null... | Out-Null)。

    预期的输出由此代码产生:

    Function MyStringFunc([String]$line) {
        $r = New-Object -TypeName "System.Collections.Generic.List``1[[System.String]]";
        $sb = New-Object -TypeName "System.Text.StringBuilder";
    
        foreach ($c in [char[]]$line) {
            $null = $sb.Append($c);
            $r.Add($sb.ToString());
        }
    
        return $r;
    }
    
    $line1 = "123";
    $a = MyStringFunc $line1;
    $a
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 2014-07-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多