Overriding Equals Method in Structs

I was looking for guidelines for structures, but all I can find are classes.

At first it seemed to me that I did not need to check whether the passed object was empty, because structures are value types and cannot be null. But now, when I think about it, as an equal sign,

public bool Equals(object obj) 

It seems that there is nothing that would prevent my structure from trying to compare it with an arbitrary reference type.

My second point is about casting, which I (I think) must do before comparing my private fields in my structure. How should I use an object for my type of structure? The C # as keyword is only for reference types.

+55
equals override c # struct overriding
Mar 30 '10 at 3:24
source share
5 answers
 struct MyStruct { public override bool Equals(object obj) { if (!(obj is MyStruct)) return false; MyStruct mys = (MyStruct) obj; // compare elements here } } 
+75
Mar 30 '10 at 3:30
source share

I believe that if you use .NET 4.5 , you can use the default implementation, as indicated in the documentation :

When you define your own type, this type inherits the functionality defined by the Equals method of its base type.

ValueType.Equals : equality of values; either direct byte comparison or field comparison using reflection.

+13
May 25 '13 at 7:54
source share

In case someone wonders about the impact of boxing performance in the structure of the Nullable object (to avoid double checking from is and casts), there is some minor overhead.

tl; dr : use is and produce in this script.

 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); } } 

Results:

 BOXING EQ 8012 7973 7981 8000 NEQ 7929 7715 7906 7888 DOUBLECHECK EQ 3654 3650 3638 3605 NEQ 3310 3301 3319 3297 

Warning. This test can be ruined in many ways, although I made sure that the test code itself was not optimized in an odd way.

Looking at IL, the double check method compiles a little cleaner.

Boxing 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 

Double check 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 

Details to Roman Rainer for the fact that he noticed a mistake that really did not make me look good.

+7
02 Feb '15 at 15:46
source share

Use the is statement:

 public bool Equals(object obj) { if (obj is MyStruct) { var o = (MyStruct)obj; ... } } 
+5
Mar 30 '10 at 3:30
source share

Adding to existing answers.

Can you still have NULL values ​​if you add? after the structure name (this works for each value object)

 int? 

Casting is also performed by calling (MyStructName)variableName

0
Mar 30
source share



All Articles