如果任何人的疑惑拳擊在可空對象的結構的性能損失(以避免is
double類型檢查和演員),還有是一個不可忽略的開銷。
tl; dr:在這種情況下使用is
&。
struct Foo : IEquatable<Foo>
{
public int a, b;
public Foo(int a, int b)
{
this.a = a;
this.b = b;
}
public override bool Equals(object obj)
{
#if BOXING
var obj_ = obj as Foo?;
return obj_ != null && Equals(obj_.Value);
#elif DOUBLECHECK
return obj is Foo && Equals((Foo)obj);
#elif MAGIC
?
#endif
}
public bool Equals(Foo other)
{
return a == other.a && b == other.b;
}
}
class Program
{
static void Main(string[] args)
{
RunBenchmark(new Foo(42, 43), new Foo(42, 43));
RunBenchmark(new Foo(42, 43), new Foo(43, 44));
}
static void RunBenchmark(object x, object y)
{
var sw = Stopwatch.StartNew();
for (var i = 0; i < 100000000; i++) x.Equals(y);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
結果:
BOXING
EQ 8012 7973 7981 8000
NEQ 7929 7715 7906 7888
DOUBLECHECK
EQ 3654 3650 3638 3605
NEQ 3310 3301 3319 3297
警告:此測試可能會在許多方面是有缺陷的,雖然我沒有驗證碼基準本身以奇怪的方式未進行優化。
看着IL,雙重檢查方法編譯一點清潔。
拳擊IL:
.method public hidebysig virtual
instance bool Equals (
object obj
) cil managed
{
// Method begins at RVA 0x2060
// Code size 37 (0x25)
.maxstack 2
.locals init (
[0] valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo> obj_
)
IL_0000: ldarg.1
IL_0001: isinst valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>
IL_0006: unbox.any valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>
IL_000b: stloc.0
IL_000c: ldloca.s obj_
IL_000e: call instance bool valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>::get_HasValue()
IL_0013: brfalse.s IL_0023
IL_0015: ldarg.0
IL_0016: ldloca.s obj_
IL_0018: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>::get_Value()
IL_001d: call instance bool StructIEqualsImpl.Foo::Equals(valuetype StructIEqualsImpl.Foo)
IL_0022: ret
IL_0023: ldc.i4.0
IL_0024: ret
} // end of method Foo::Equals
仔細檢查IL:
.method public hidebysig virtual
instance bool Equals (
object obj
) cil managed
{
// Method begins at RVA 0x2060
// Code size 23 (0x17)
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst StructIEqualsImpl.Foo
IL_0006: brfalse.s IL_0015
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: unbox.any StructIEqualsImpl.Foo
IL_000f: call instance bool StructIEqualsImpl.Foo::Equals(valuetype StructIEqualsImpl.Foo)
IL_0014: ret
IL_0015: ldc.i4.0
IL_0016: ret
} // end of method Foo::Equals
道具羅馬萊納爲察覺真的沒有讓我看好了一個錯誤。
來源
2015-02-02 15:46:13
tne
只是說明你鼓勵避免.Net中的可變結構。它的設置應該堅持引用類型(類)大部分時間,並且很少使用結構。 – 2010-03-30 03:34:40
我第二。使用不可變結構*不帶*子類型。然後Equals和==對於給定的接收者(左側值)應該是相同的,其中實現中唯一的區別是Equals需要'is'檢查,然後爲簡單起見,將調度爲==。因此,兩個合同都得到履行,意外情況得到緩解。 – 2010-03-30 03:40:56
是的,這個結構是不可變的。我只比較一個int。 – 2010-03-30 03:51:00