System.Collections.Generic.Dictionary for每个顺序

本文关键字:顺序 for Dictionary Collections Generic System | 更新日期: 2023-09-27 18:15:36

查看一些遍历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

System.Collections.Generic.Dictionary for每个顺序

随机和任意的实现细节。它是明确地不保证,不应该依赖。它可以在不同的。net框架和不同的实现(mono等)上表现不同。

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

当字典被枚举时,数组也被枚举。这解释了您所看到的顺序。

不要依赖这个行为。如果微软改变实现,它将来可能会改变。