System.Collections.Generic.Dictionary foreach命令

时间:2015-10-01 16:18:31

标签: c# .net dictionary foreach

查看迭代字典的一些代码,看起来代码依赖于按键值的升序访问,使用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

2 个答案:

答案 0 :(得分:9)

偶然和任意的实施细节。 明确不保证,不应该依赖。它可能在不同的.NET框架和不同的实现(单声道等)上表现不同。

答案 1 :(得分:1)

我查看了当前的实现。字典在内部使用两个数组:一个用于包含键,值和其他信息的条目,另一个使用哈希代码作为索引并包含条目数组中相应条目的索引(称为buckets)。存储桶信息确实是未排序和无序的,但条目数组是有序的,即它按照它们已添加到字典中的顺序保存条目。但是,这些条目没有排序,即如果以未排序的方式添加条目,它们将保持未排序。

枚举字典时,将枚举entries数组。这解释了你看到的顺序。

不要依赖这种行为。如果微软改变实施方式,它可能会在未来发生变化。