2015-10-01 69 views
1

尋找在該遍歷一個字典,並且看來該代碼由升序鍵值的順序,使用的foreach依賴於訪問一些代碼。System.Collections.Generic.Dictionary的foreach順序

MSDN文檔指出「對於枚舉的目的,字典中的每個項目被作爲表示一個值及其鍵中KeyValuePair結構進行處理。在所返回的項目的順序是不確定的。」。

然而,在執行過程中的代碼做訪問每個KeyValuePair在「正確」的順序。

我已經更新的代碼來明確訂購的項目,但有興趣,如果任何人有一個解釋,爲什麼原來的代碼表現爲筆者的預期。

#if pl 
my $hdr = ' 
    Test script. 
    Once per session, run 
    "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat" 
    or equivalent. 
    Run "perl FooInstallTest.cs". 
'; 

use strict; 
use Test::More tests => 2; 
use sigtrap 'handler', \&cleanup, 'normal-signals'; 

my @reference = (qw(
)); 


sub main { 
    my $ret; 
    my $prog = "FooInstallTest.exe"; 

    my $cmd = 
    "csc /debug " . 
    "/nologo " . 
    "/platform:x86 " . 
    "/out:FooInstallTest.exe " . 
    "/d:TRACE /d:DEBUG " . 
    "/define:FooInstallTest " . 
    "" 
    ; 

    foreach my $reference (@reference) { 
     $cmd .= ('/reference:' . $reference . " "); 
    } 

    $cmd .= 
    "FooInstallTest.cs " . 
    ""; 

    unlink($prog); 

    foreach my $reference (@reference) { 
     system("xcopy /y $reference ."); 
    } 

    1 && print("$cmd\n"); 
    $ret = system($cmd); 
    is($ret, 0, "Compile."); 

    my $run = $prog; 
    1 && print("$run\n"); 
    $ret = system($run); 
    is($ret, 0, "Run."); 

    cleanup(); 
} 

sub cleanup { 
    foreach my $reference (@reference) { 
     $reference =~ s/.*\\//; 
     (-e $reference) && (unlink($reference)); 
    } 
} 

main(); 

__END__ 
#endif 

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Collections.Concurrent; 
using System.Data; 
using System.Data.Linq; 
using System.Diagnostics; 
using System.Linq; 

#if FooInstallTest 
#endif 


#if FooInstallTest 
public class FooInstallTest { 

    public static int Main(String[] args) { 
     FooInstallTest foo_install_test = new FooInstallTest(); 
     return foo_install_test.main(); 
    } 

    public int main() { 
     UpdateFooDB(); 
     return 0; 
    } 

    void UpdateFooDB() { 
     string serverPath = 
     @"Server=.\sqlexpress;Trusted_Connection=True;Database=foo;"; 

     System.Collections.Generic.Dictionary<double, string> upgrades = 
     new System.Collections.Generic.Dictionary<double, string> { 
     {1.2, "foo_1_2.sql"}, 
     {1.3, "foo_1_3.sql"}, 
     {1.6, "foo_1_6.sql"}, 
     {1.7, "foo_1_7.sql"}, 
     {1.8, "foo_1_8.sql"}, 
     {1.9, "foo_1_9.sql"}, 
     {2.0, "foo_2_0.sql"}, 
     {2.01, "foo_2_01.sql"}, 
     {2.02, "foo_2_02.sql"}, 
     {2.03, "foo_2_03.sql"}, 
     {2.031, "foo_2_031.sql"}, 
     {2.032, "foo_2_032.sql"}, 
     {2.033, "foo_2_033.sql"}, 
     {2.034, "foo_2_034.sql"}, 
     {2.035, "foo_2_035.sql"}, 
     {2.036, "foo_2_036.sql"}, 
     {2.037, "foo_2_037.sql"}, 
     {2.038, "foo_2_038.sql"}, 
     {2.039, "foo_2_039.sql"}, 
     {2.040, "foo_2_040.sql"}, 
     {2.041, "foo_2_041.sql"}, 
     {2.042, "foo_2_042.sql"}, 
     }; 
     UpdateDatabase(serverPath, upgrades); 
    } 

    void UpdateDatabase(
    string serverPath, 
    System.Collections.Generic.Dictionary<double, string> upgrades 
    ) { 
     //ing (SqlConnection conn = new SqlConnection(serverPath)) 
     { 
     //nn.Open(); 

     double targetVersion = upgrades.LastOrDefault().Key; 
     //uble currentVersion = GetVersion(conn); 
     double currentVersion = 1.0; 

     string diagMessage = String.Format(
      "Installer: Update Database: current: [{0}], target: [{1}]" 
      ,currentVersion.ToString() 
      ,targetVersion.ToString() 
     ); 
     Console.WriteLine(diagMessage); 

     foreach (var item in upgrades) { 
      if ((currentVersion < targetVersion) && (currentVersion < item.Key)) { 
       diagMessage = String.Format(
       "Execute Update: current: [{0}], key: [{1}], file: [{2}]" 
       ,currentVersion.ToString() 
       ,item.Key.ToString() 
       ,item.Value.ToString() 
       ); 
       Console.WriteLine(diagMessage); 
       //ecuteSqlFile(conn, item.Value); 
       currentVersion = item.Key; 
      } 
     } 
     } 
    } 
} 

#endif 
+1

就像一個簡單的「SortedDictionary」一樣 - https://msdn.microsoft.com/en-us/library/f7fta44c(v=vs.110).aspx – Lloyd

+0

什麼是*「the正確的順序」*。你如何定義正確性?當文檔明確指出時,您不應該依賴實現細節。 –

回答

1

我看了一下當前的實現。字典在內部使用兩個數組:一個用於包含鍵,值和其他信息的條目,另一個使用散列碼作爲索引幷包含條目數組中相應條目的索引(稱爲buckets)。桶信息確實是未排序的和無序的,但是這些entries數組是有序的,即它按照它們被添加到字典中的順序保持條目。然而,這些條目並未排序,即如果以未排序的方式添加條目,它們將保持未排序。

當字典中列舉的條目陣列枚舉。這解釋了你所看到的順序。

不要依賴這種行爲。如果微軟改變實施方式,未來可能會改變。

+0

@ojc邊既成事實。這當然可以解釋它。我已經修改了測試程序,以任意順序實例化字典,並且如您所預測的那樣,在用foreach進行迭代時確實看到了相同的添加順序。 (正如OP所述,代碼已經更新,以保證所需的行爲,儘管原創作者是幸運的。) – ewd

9

通過機會和任意的實現細節。這是明確不保證,不應該依靠。它可能在不同的.NET框架和不同的實現(單聲道等)上表現不同。

+0

22個項目按偶然或abitrarity升序排列?我會告訴你它比Boltzmann Brain更可能,但是又如何以一種散列表的形式實現這種類型的行爲呢? (我想這一定是他們都在同一個桶中結束。) – ewd

+1

@ewd歡迎您玩得開心拆卸框架庫來回答這個問題,但最終是不是對我很重要 –

相關問題