查看迭代字典的一些代码,看起来代码依赖于按键值的升序访问,使用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
答案 0 :(得分:9)
偶然和任意的实施细节。 明确不保证,不应该依赖。它可能在不同的.NET框架和不同的实现(单声道等)上表现不同。
答案 1 :(得分:1)
我查看了当前的实现。字典在内部使用两个数组:一个用于包含键,值和其他信息的条目,另一个使用哈希代码作为索引并包含条目数组中相应条目的索引(称为buckets
)。存储桶信息确实是未排序和无序的,但条目数组是有序的,即它按照它们已添加到字典中的顺序保存条目。但是,这些条目没有排序,即如果以未排序的方式添加条目,它们将保持未排序。
枚举字典时,将枚举entries数组。这解释了你看到的顺序。
不要依赖这种行为。如果微软改变实施方式,它可能会在未来发生变化。