我发布这个是迂腐的.我不喜欢与Dictionary的接口,因为这种非常常见的访问需要付出代价 - 如果你最常见的情况是触摸已经存在的元素,你必须哈希并查找你的值3次.不相信我?我在这里写了DK的解决方案:
static void AddInc(Dictionarydict, string s) { if (dict.ContainsKey(s)) { dict[s]++; } else { dict.Add(s, 1); } }
当放入IL - 你得到这个:
L_0000: nop L_0001: ldarg.0 L_0002: ldarg.1 L_0003: callvirt instance bool [mscorlib]System.Collections.Generic.Dictionary`2::ContainsKey(!0) L_0008: ldc.i4.0 L_0009: ceq L_000b: stloc.0 L_000c: ldloc.0 L_000d: brtrue.s L_0028 L_000f: nop L_0010: ldarg.0 L_0011: dup L_0012: stloc.1 L_0013: ldarg.1 L_0014: dup L_0015: stloc.2 L_0016: ldloc.1 L_0017: ldloc.2 L_0018: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2 ::get_Item(!0) L_001d: ldc.i4.1 L_001e: add L_001f: callvirt instance void [mscorlib]System.Collections.Generic.Dictionary`2 ::set_Item(!0, !1) L_0024: nop L_0025: nop L_0026: br.s L_0033 L_0028: nop L_0029: ldarg.0 L_002a: ldarg.1 L_002b: ldc.i4.1 L_002c: callvirt instance void [mscorlib]System.Collections.Generic.Dictionary`2 ::Add(!0, !1) L_0031: nop L_0032: nop L_0033: ret
它调用ContainsKey,get_item和set_item,所有这些都散列并查找.
我写了一些不太漂亮的东西,它使用了一个包含int的类,并且该类允许你对它产生副作用(由于struct复制语义,你不能真正使用结构而不会产生相同的惩罚).
class IntegerHolder { public IntegerHolder(int x) { i = x; } public int i; } static void AddInc2(Dictionarydict, string s) { IntegerHolder holder = dict[s]; if (holder != null) { holder.i++; } else { dict.Add(s, new IntegerHolder(1)); } }
这给你以下IL:
L_0000: nop L_0001: ldarg.0 L_0002: ldarg.1 L_0003: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2::get_Item(!0) L_0008: stloc.0 L_0009: ldloc.0 L_000a: ldnull L_000b: ceq L_000d: stloc.1 L_000e: ldloc.1 L_000f: brtrue.s L_0023 L_0011: nop L_0012: ldloc.0 L_0013: dup L_0014: ldfld int32 AddableDictionary.IntegerHolder::i L_0019: ldc.i4.1 L_001a: add L_001b: stfld int32 AddableDictionary.IntegerHolder::i L_0020: nop L_0021: br.s L_0033 L_0023: nop L_0024: ldarg.0 L_0025: ldarg.1 L_0026: ldc.i4.1 L_0027: newobj instance void AddableDictionary.IntegerHolder::.ctor(int32) L_002c: callvirt instance void [mscorlib]System.Collections.Generic.Dictionary`2 ::Add(!0, !1) L_0031: nop L_0032: nop L_0033: ret
哪个调用get_item一次 - 在对象存在的情况下没有额外的散列.我有点邋and并使该字段公开,以避免方法调用属性访问.
如果是我,我会将这个整体功能包装到自己的类中,并从公共视图中隐藏IntegerHolder类 - 这是一个限制版本:
public class CountableItem{ private class IntegerHolder { public int i; public IntegerHolder() { i = 1; } } Dictionary dict = new Dictionary (); public void Add(T key) { IntegerHolder val = dict[key]; if (val != null) val.i++; else dict.Add(key, new IntegerHolder()); } public void Clear() { dict.Clear(); } public int Count(T key) { IntegerHolder val = dict[key]; if (val != null) return val.i; return 0; } // TODO - write the IEnumerable accessor. }