编译器会优化这段代码还是集合会在每次方法调用后被初始化?
private string Parse(string s)
{
var dict = new Dictionary<string, string>
{
{"a", "x"},
{"b", "y"}
};
return dict[s];
}
如果答案是否定的,我建议使用以下解决方案:在C#中创建常量字典。
编译器会优化这段代码还是集合会在每次方法调用后被初始化?
private string Parse(string s)
{
var dict = new Dictionary<string, string>
{
{"a", "x"},
{"b", "y"}
};
return dict[s];
}
Parse:
IL_0000: newobj System.Collections.Generic.Dictionary<System.String,System.String>..ctor
IL_0005: stloc.1 // <>g__initLocal0
IL_0006: ldloc.1 // <>g__initLocal0
IL_0007: ldstr "a"
IL_000C: ldstr "x"
IL_0011: callvirt System.Collections.Generic.Dictionary<System.String,System.String>.Add
IL_0016: ldloc.1 // <>g__initLocal0
IL_0017: ldstr "b"
IL_001C: ldstr "y"
IL_0021: callvirt System.Collections.Generic.Dictionary<System.String,System.String>.Add
IL_0026: ldloc.1 // <>g__initLocal0
IL_0027: stloc.0 // dict
IL_0028: ldloc.0 // dict
IL_0029: ldarg.1
IL_002A: callvirt System.Collections.Generic.Dictionary<System.String,System.String>.get_Item
IL_002F: ret
正如您所看到的,它每次调用newobj
来分配Dictionary<K,V>
,加载本地变量并每次调用Dictionary.Add
在两个本地变量上(这是语法糖等效于调用Add
)。 它没有深入了解类型以缓存对象的创建。
Dictionary
是什么,对于它来说,Dictionary
只是一个普通的类,所以它不知道在这种特殊情况下可以重用实例。public class Something
{
private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>
{
{"a", "x"},
{"b", "y"}
}
private string Parse(string s)
{
return _dict[s];
}
}
这种方法有效是因为您知道对象的作用,并且知道它永远不会被修改。
请记住以下语法:
var dict = new Dictionary<string, string>
{
{"a", "x"},
{"b", "y"}
}
这只是一种语法糖,其实就等同于:
var dict = new Dictionary<string, string>();
dict.Add("a", "x");
dict.Add("b", "y");
IEnumerable
Add
方法。switch
语句,但是 Dictionary
的方法可以更加灵活。例如,你可能想要使用不同的相等比较器(如 StringComparer.OrdinalIgnoreCase
),最好让 Dictionary
使用合适的比较器来处理,而不是像 switch(value.ToLowerInvariant())
这样的代码。Dictionary
呢? - astefDictionary
有什么特别之处吗?为什么不用HashSet
,或者OrderedDictionary
,或者ConditionalWeakTable
呢?这将是无穷无尽的。最好只有一些特殊的已知情况(例如Task<T>
)。 - Lucas TrzesniewskiAdd
方法有什么特别之处,以至于要用初始化器来替换它?老实说,我不知道。只是在问一下 :) - astefAdd
调用替换它,但方法本身并没有什么特别之处。它可以做任何事情。编译器不关心,它只为你提供语法糖。 - Lucas Trzesniewski不,就目前而言,C# 不会以任何方式“优化”此代码 - 而且我严重怀疑这种情况是否会发生。
虽然你可能会认为这段特定的代码可以进行优化,但实际上它是一个边界情况,不太容易在编译时确定。举个反例 - 如果你的字符串文字之一是另一个类的成员呢?如果你有一个自定义字典(现有字典类没有特殊处理),它的构造函数做了一些奇怪的事情呢?
new Dictinary<String, String> { { "x", SOME_CLASS.MEMBER } }
。现在当SOME_CLASS.MEMBER
更改时,对Parse
的后续调用应该使用新值——因此无法进行优化。 - decPL