Geeks With Blogs
Scott Van Vliet Once a Developer, Always a Developer

Update 2010-03-23 – Sorry, but the images and downloads were hosted on a server that is no longer available.  I will try to find the sample code bits and images on a backup sometime!

I’ve noticed some very weird behavior when comparing boxed value types, referenced as object.  Consider the following code.

 

object a = "foo";

object b = "foo";

 

bool matchRefType = (a == b);

 

object x = 1;

object y = 1;

 

bool matchValueType = (x == y);

 

The first Boolean value will return true, as expected.  However, the second will return false.  What’s more, when running this code in Debug, the following statement returns as expected.

 

If I unbox the value types in code explicitly, the following statement will return true, which is the desired outcome.

 

bool matchValueType = ((int)x == (int)y);

 

The problem here is that the values I am comparing may be of any value type (or reference type for that matter.)  I could use Reflection to perform a psuedo unboxing of the value types; however, this would still return a reference.  I know it must be doable from code if the Command Window can do it :)


If you have come across this before, please share your much valued insight.  Thanks!

Posted on Wednesday, May 25, 2005 6:46 AM C# | Back to top


Comments on this post: Odd Behavior While Boxing Value Types in C# 1.1

# re: Odd Behavior While Boxing Value Types in C# 1.1
Requesting Gravatar...
Indeed, you should use .equals for value equality. By default, operator == (MSIL "ceq") performs a reference equality check for reference types.
<br>
<br>The behaviour you're seeing is due to string interning performed the compiler. Whenever you have two identical string literals, only one string is actually stored in the metadata, and then created at runtime, assigning the same string reference to all uses of the literal.
<br>
<br>string a = &quot;foo&quot;;
<br>string b = &quot;foo&quot;;
<br>
<br>Console.Write(a == b);
<br>/*
<br> * True, as this will call op_Equality for System.String via overloading
<br> */
<br>
<br>/*
<br> * This is also true, but because the compiler has (fundamentally) generated
<br> *
<br> * string tmp = &quot;foo&quot;;
<br> * string a = tmp;
<br> * string b = tmp;
<br> */
<br>Console.Write((object)a == (object)b);
<br>
<br>This &quot;interning&quot; optimisation is one of the main reasons why string objects are immutable. If you try your test with other reference types, you should see the expected failure. Indeed.
<br>
<br>object a = new System.Text.StringBuilder(1);
<br>object b = new System.Text.StringBuilder(1);
<br>
<br>bool matchRefType = (a == b);
<br>
<br>Results in false, as the two references are different, and there is no operator== for StringBuilder.
<br>
<br>adamw
Left by Adam Wright on May 25, 2005 11:52 AM

# re: Odd Behavior While Boxing Value Types in C# 1.1
Requesting Gravatar...
Thanks for your feedback. Although true for reference types, that is NOT the problem area. The problem occurrs when comparing value types.
<br>
<br>Using .Equals() will perform the boxed value type comparison and return the appropriate value; HOWEVER, note that the odd behavior originally posted here was that the == comparison returned the correct value when evaluated in the Command Window.
<br>
<br>Doing a dump in ILDASM reveals the following; when comparing with ==, the only IL indicative of such a boxed compare generated is:
<br>
<br>bne.un.s
<br>
<br>Alternatively, when using .Equal(), the following IL is generated:
<br>
<br>callvirt instance bool [mscorlib]System.Object::Equals(object)
<br>
<br>I guess the point is, there has to be an explanation of why .Equals() works for value types, while == does not (and does in the Command Window.)
<br>
<br>Thanks again for any insight.
Left by Scott Van Vliet on May 25, 2005 12:17 PM

# re: Odd Behavior While Boxing Value Types in C# 1.1
Requesting Gravatar...
I stated why == does not work for *boxed* value types - operator== performs reference equality, and both boxes are different. Equals works because it compares bitwise value equality for value types (though it still, by default, compares reference equality for reference types). The ValueType equals operator will be invoked even in a boxed situation - Equals is a virtual function, and the underlying type of a boxed value type is still it's value class.
<br>
<br>Regarding the command window, it's more a debugging tool, and less a robust expression evaluator. Indeed, it often will fail to evaluate properly formed expressions. As far as I know, it has limited hard coded syntax &quot;optimised&quot; for least-suprise debugging. I guess they thought that bitwise comparisions for value types all the time would be the most sensible (I guess they're using .Equals as the backend for their == operator).
<br>
<br>You can't trust it as far as you can throw it. As as Microsoft doesn't support throwing windows, you can't trust it at all. I stopped using it years ago.
<br>
<br>adamw
Left by Adam Wright on May 25, 2005 1:02 PM

# re: Odd Behavior While Boxing Value Types in C# 1.1
Requesting Gravatar...
Adam,
<br>
<br>Thanks for your feedback. I think I may have misread your original comment, as you used all reference types in your examples. Thanks for the clarification on the fact that Equals() uses bitwise comparison, as this makes much more sense.
<br>
<br>Regards,
<br>
<br>Scott
Left by Scott Van Vliet on May 26, 2005 4:56 PM

Your comment:
 (will show your gravatar)


Copyright © svanvliet | Powered by: GeeksWithBlogs.net