重叠等值法在结构中的应用

我已经寻找结构的压倒一切的指导方针,但我能find的只是课程。

起初,我想我不会检查,看看传递的对象是否为null,因为结构是值types,不能为空。 但现在我想起来了,就像平等签名一样

public bool Equals(object obj) 

似乎没有任何东西阻止我的结构的用户试图比较它与任意的引用types。

我的第二点是关于在我比较我的结构中的私有字段之前,我想(我想)。 我该如何将对象转换为我的结构types? C#的关键字似乎只适用于引用types。

 struct MyStruct { public override bool Equals(object obj) { if (!(obj is MyStruct)) return false; MyStruct mys = (MyStruct) obj; // compare elements here } } 

我想,如果使用.NET 4.5 ,可以使用文档中提到的默认实现:

在定义自己的types时,该types将inheritance由基types的Equals方法定义的function。

ValueType.Equals :值相等; 可以直接逐字节比较或使用reflection进行逐场比较。

使用is运算符:

 public bool Equals(object obj) { if (obj is MyStruct) { var o = (MyStruct)obj; ... } } 

如果有人想知道Nullable对象中的结构的性能命中(为了避免来自is和cast的doubletypes检查),有一个不可忽略的开销。

tl; dr :在这种情况下使用&cast。

 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 

警告:这个testing在许多方面可能有缺陷,尽pipe我确实证实了基准testing代码本身没有以一种奇怪的方式进行优化。

看看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 

道具罗马赖纳发现一个错误,真的不让我看起来不错。

添加到现有的答案。

你仍然可以有空值,如果你追加一个? 之后的结构名称(这适用于每个值对象)

 int? 

铸造也通过调用(MyStructName)variableName