if ( T == default(T) ) {}You actually need either
if ( object.Equals(value, default(T)) ) {}or (according to the SO post more efficient - though I've not checked this)
if (EqualityComparer.Default.Equals(value,default(T))) {}
UPDATE:
I was asked the question: “I assume that this is to avoid evaluating the reference (pointer) rather than the value?”
I think that would depend on the implementation of the compare method for the type being used and as the SO post suggests this isn’t the whole story… to take a step back…
The reason for this roundabout way of checking that the value (T) is empty is logically because T could be either value or reference type, so a method is needed which can be made to deal with both value and reference types.
As you suggest Object.Equals() is a compares pointers (references), so if T was a value type it would first need boxing (first needs to be turned into a reference type), you can see this in the IL (example1 below – a contrived and nonsense function!) …
Also note in the IL that “default(T)” statement means that T is boxed too – this will be because T can be either reference or value type, so the IL boxes to force the issue (actually this surprises me a bit, I was thinking the compiler would be able to work this out based on the use, but maybe that’s asking a lot?!).
So to go back to the original post (and a check in MSDN confirms this) the use of “EqualityComparer
Note: I haven’t dug down any deeper, it could well be that if the code falls back to Object.Equals for a value type then boxing will still occur.
Examples:
public static T Foo() { T r = default(T); int x=0; string y = ""; bool result = object.Equals(x, default(T)); return r; }
(abridged)
IL_0012: box [mscorlib]System.Int32
IL_0017: ldloca.s CS$0$0001
IL_0019: initobj !!T
IL_001f: ldloc.s CS$0$0001
IL_0021: box !!T
IL_0026: call bool [mscorlib]System.Object::Equals(object, object)
public static T Foo() { T r = default(T); int x=0; string y = ""; bool b = EqualityComparer .Default.Equals(r, default(T)); return r; }
(abridged)
IL_0001: ldloca.s r
IL_0003: initobj !!T
.
.
IL_0019: initobj !!T
IL_001f: ldloc.s CS$0$0001
IL_0021: callvirt instance bool class [mscorlib]System.Collections.Generic.EqualityComparer`1::Equals(!0, !0)
1 comment:
..and this is where I get quite annoyed with .net as the first option is so much more readable than the last!
Post a Comment