2011-06-03 48 views
3

原諒標題,我真的不知道如何解釋我所看到的。一個循環內的Powershell值失去其價值

示例代碼:

$SampleValues = 1..5 
    $Result = "" | Select ID 
    $Results = @() 

    $SampleValues | %{ 
     $Result.ID = $_ 
     $Results += $Result 
    } 

$Results 

這是相當簡單:

  • 創建一個陣列在循環
  • 可以使用5個號碼與被叫ID
  • NoteProperty創建臨時變量
  • 創建一個空數組來存儲結果
  • 遍歷5個數字中的每一個a將它們分配給一個臨時變量,然後將其附加到一個數組。

預期的結果是1,2,3,4,5,但運行時它返回5,5,5,5,5

這是從更復雜的腳本採取了準系統例子,我試圖找出結果是什麼。在每次迭代中,所有已添加到$ Results的元素都將其值更新爲最新值。我測試過將所有內容強制轉換爲$ Script:或$ Global:scope並獲得相同的結果。

我發現的唯一解決方案是以下,它將$ Result聲明移動到循環中。

$SampleValues = 1..5 
    $Results = @() 

$SampleValues | %{ 
    $Result = "" | Select ID 
    $Result.ID = $_ 
    $Results += $Result 
    } 

這是有效的(你得到1,2,3,4,5作爲結果)。它看起來像$ Results只是持有對單個$ Result對象的多個引用,但爲什麼將它移入循環可修復問題?在這個例子中,$ Result是一個字符串,所以它可能會在每次迭代時創建一個新對象,但即使當我強制$ Result是一個整數時(它不應該重新創建一個新對象,因爲整數不像字符串那樣不可變)仍然解決了這個問題,我得到了我期望的結果。

如果有任何人有任何洞察,到底爲什麼這解決了這個問題,我一直很好奇。我有很多替代方案可以實施,但沒有具體理解爲什麼這種方式會以這種方式影響我。

回答

8

它通過進入循環來修復問題,因爲那麼您每次都會創建一個新的$ Result對象,而不是在同一個對象上改變一個值(在數組中引用5次)。

它與您是否使用"" | Select ID123 | Select ID沒有任何關係,因爲它只是成爲PSCustomObject上的一種屬性,它仍然是引用類型而不是值類型。

請記住,PowerShell的內部都是.NET。下面是一些C#這是類似於什麼Powershell的中,導致所有5S(希望你知道C#)你的第一個例子是這樣做的:

var SampleValues = new []{1,2,3,4,5}; 
var Result = new CustomObject(){ ID = "" }; 
var Results = new List<Object>(); 

foreach (var _ in SampleValues) { 
    Result.ID = _; 
    Results.Add(Result); 
} 

希望你可以看到移動var Result = new CustomObject(){ ID = "" }foreach循環內將使其更好地工作,並且在Powershell中也有相同的概念。

+0

喬爾,感謝您的評論。 整數是值類型。 我試過'結果= 0 |選擇ID',結果和ID都是Int32。這是困惑我,因爲我仍然有5,5,5,5,5。 – Eric 2011-06-03 18:12:58

+0

原諒雙重評論,我似乎無法編輯我的初始答覆。 這就是我指的。如果$ Result和ID都是Int32,那麼它們是值類型,而不是引用類型,那麼$ Results存儲的對象引用是什麼? $結果| gm 類型名稱:Selected.System.Int32 名稱MemberType定義 ---- ---------- ---------- Equals方法bool Equals(System.Object obj ) GetHashCode的方法INT GetHashCode()方法 GetType方法的類型的GetType() ToString方法字符串的ToString() ID NoteProperty System.Int32 ID = 1 – Eric 2011-06-03 18:21:16

+1

如果你'$結果= 0 |選擇ID','$ Result.GetType()'返回基類型爲'System.Object'的'PSCustomObject'。 '$ Result.ID'最初應該是'null'。如果分配一個整數('$ Result.ID = 0'),'$ Result.GetType()'仍然是相同的,但是現在'$ Result.ID.GetType()'返回'Int32',基類型爲'System。 ValueType'。 – 2011-06-03 18:22:02

1

在這個例子中$結果是一個字符串,所以它可能會創建一個新的對象每次迭代,但即使當我強制$結果是一個整數(它不應該重新創建一個新的對象,因爲整數不是不可變的像一個字符串)它仍然解決了問題,我得到了我期望的結果。

其實在你的例子中$ Result不是一個字符串。它是一個通用對象,其中一個propery(ID)是一個字符串。

Powershell變量有兩種類型 - 值和參考。一個字符串或整數是通過值傳遞的,一個對象通過引用傳遞。通過addind $ result到$ results 5次,你得到5個引用到一個$ result對象,而不是5個不同的對象。

如果我們的$ result.id屬性(整數/價值型)添加到$結果,而不是$結果對象,我們得到:

$SampleValues = 1..5 
    $Result = "" | Select ID 
    $Results = @() 

    $SampleValues | %{ 
     $Result.ID = $_ 
     $Results += $Result.ID 
    } 

1 
2 
3 
4 
5