Code Comments
Programming Forum and web based access to our favorite programming groups.Hello,
I've recently transfered from vb.net to c#. I'm witnessing some
confusing behaviour that I'm hoping someone will be able to explain to
me.
In the following code, both of these variables return a value of type
'object'.
* ((iOPWLifecycle)value).Key
* key
At runtime, both of the above contain matching string objects, "abc",
however the following code snippent is evaluating them as not equal.
if (((iOPWLifecycle)value).Key != key)
{
// the thread is stepping into the exception code.
throw new Exception("Expected key match");
}
However, if I change the code to the following, the code runs as I
expected, only raising the error when the values are different.
if (!((iOPWLifecycle)value).Key.Equals(key))
{
throw new Exception("Expected key match");
}
In the first example, if I explicity cast both of the values to
'string' objects, the code works as expected.
Whilst I've found a workaround, I am thoroughly
as to why c#
behaves as such. If both variables return string objects, why doesn't
c# correctly apply the default string comparison?
If someone could point me in the right direction with this, I would
greatly appreciate it. I can see how not understanding this properly
would be asking for a stack of 'nasty' bugs.
Thanks in advance,
Damien Sawyer
Post Follow-up to this message
<damiensawyer@yahoo.com.au> wrote in message
news:1116479397.907615.43230@g43g2000cwa.googlegroups.com...
> Hello,
>
> I've recently transfered from vb.net to c#. I'm witnessing some
> confusing behaviour that I'm hoping someone will be able to explain to
> me.
>
> In the following code, both of these variables return a value of type
> 'object'.
> * ((iOPWLifecycle)value).Key
> * key
>
> At runtime, both of the above contain matching string objects, "abc",
> however the following code snippent is evaluating them as not equal.
>
> if (((iOPWLifecycle)value).Key != key)
> {
> // the thread is stepping into the exception code.
> throw new Exception("Expected key match");
> }
>
> However, if I change the code to the following, the code runs as I
> expected, only raising the error when the values are different.
>
> if (!((iOPWLifecycle)value).Key.Equals(key))
> {
> throw new Exception("Expected key match");
> }
>
>
> In the first example, if I explicity cast both of the values to
> 'string' objects, the code works as expected.
>
>
> Whilst I've found a workaround, I am thoroughly
as to why c#
> behaves as such. If both variables return string objects, why doesn't
> c# correctly apply the default string comparison?
>
> If someone could point me in the right direction with this, I would
> greatly appreciate it. I can see how not understanding this properly
> would be asking for a stack of 'nasty' bugs.
>
> Thanks in advance,
>
>
>
> Damien Sawyer
>
I cannot get a code example that works the way you describe. I tried adding
the items to a hashtable, casting to objects, looping through, creating new
objects that have the string "abc" in them, all evaluate to being equal as
expected. Can you produce a simple example that demonstrates the behaviour
you mention?
Lorad
Post Follow-up to this messageThis happens because of the way that overloads are handled versus the way that overrides are handled. "Overload" means that there are several method with the same name and different parameter lists. The != operator is defined many times for many different types, the only difference being that the parameter types (left-hand-side, right-hand-side) are different in each case. The != operator cannot possibly be overridden because it's static, and static classes, methods, and properties don't participate in inheritance. "Override" means that a child class has provided a new implementation for a virtual method defined farther up the class hierarchy. The Equals method is overridden in the String class (since it was originally defined in the Object class). Here is the critical concept: which method _overload_ to call is determined by the compiler. Which version of an _overridden_ method to call is determined at run time. So, here is some code to illustrate: string temp = "a"; string a = "abc"; string b = temp + "b" + "c"; object o = a; object p = b; if (o != p) ... At this point, the compiler must decide which version of != to call, since the choice between various != operators is based on method overloading. The compiler _has no idea_ what type of object o and p refer to. Remember, this is not run time, when o and p point to real, instantiated objects in memory. This is compile time, and all the compiler knows is that o is an object and p is an object. So, it calls the method (optimized to a single instruction, but conceptually it's a method): public static bool operator != (object lhs, object rhs) The implementation of != provided by Object is to compare addresses. Since o and p contain different addresses*, they compare as not equal. However, if you say: if (!o.Equals(p)) you are now calling an virtual method, Equals, which is overridden in String. The compiler decides to call the version of Equals for the object o that takes another Object as its argument: public bool Equals(object otherObj) but leaves the decision as to which Equals method to call (from which level in the object hierarchy) until run time, because it's a virtual method. At run time, o and p point to actual, isntantiated objects (they're Strings), so the version of Equals that ends up being called is the String.Equals method that takes an Object as its only argument. This method compares two strings as strings, and so returns true because both strings contain "abc" even though they are stored in different places in memory. * Probably the reason that Lorad couldn't reproduce this behaviour is because of "string interning". If you write code like this: string a = "abc"; stirng b = "abc"; object o = a; object p = b; if (o != p) ... Then the != operator will, in fact, compare o and p as equal. This is because the compiler recognizes that both a and b point to the same string, "abc", and so it will point both of them to the same address in memory. This in turn means that o and p will contain the same address, which means that they will compare equal, even though the comparison is an address comparison and not comparing strings. In order to get two strings containing "abc" that "live" in different places in memory, you have to calculate at least one of them, so that the compiler doesn't clue in to what's going on and intern them.
Post Follow-up to this messageIncidentally, the way to fix the code so that it works properly every
time and is easier to read, too, is like this:
string lifeCycleKey = (string)((iOPWLifecycle)value).Key;
string keyString = (string)key;
if (lifeCycleKey != keyString)
{
// the thread is stepping into the exception code.
throw new Exception("Expected key match");
}
Now the compiler knows that you are using != to compare two strings,
and will invoke the string comparison operator, which will compare the
actual string contents rather than their addresses. It's easier to
read, too.
Post Follow-up to this messageHi Bruce, Thanks for an extremely comprehensive and informative answer! You have completely removed my confusion! Out of interest, I did actually explicitly cast the values to strings and, as expected after your explanation, it worked. However, in the business problem I'm trying to solve, the 'keys' are not always strings. Indeed, I've got half a dozen custom objects that need to be compared. Anyway - thanks again for your detailed answer. I think that C# is slowly growing on me :-) DS
Post Follow-up to this messageYou have probably already figured this out, but for the benefit of such posterity as there is in a usenet group :-) > However, in the business problem I'm trying to solve, the 'keys' are not always > strings. Indeed, I've got half a dozen custom objects that need to be compared. In that case I amend my recommended solution: use the Equals method. The CLR will figure out (via virtual methods and overriding) which is the correct Equals to call to compare your two keys.
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.