what's the underlying reason this == comparison fails? (surprising result for me)
Asked Answered
F

7

7

Context: I am prototyping in prep for (maybe) converting my WinForms app to WPF.

I make very simple tree view event handler for which the code is:

var treeViewItem = (TreeViewItem)e.NewValue;
var treeViewItemTag = treeViewItem.Tag;
if (treeViewItemTag == "ViewForAMs")
{
    ObjectQuery<AccountManagerView> oq = entities.AccountManagerViews;
    var q =
        from c in oq
        select c;
    dataGrid1.ItemsSource = q.ToList();
}

and the XAML is:

<Window x:Class="AccountingWpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <DockPanel>
        <TreeView Name="treeView1" ItemsSource="{Binding Folders}"
          SelectedItemChanged="treeView1_SelectedItemChanged">
            <TreeViewItem Header="Account Manager View" Tag="ViewForAMs"/>
        </TreeView>
        <DataGrid AutoGenerateColumns="True" Name="dataGrid1" />
    </DockPanel>
</Window>

When I ran it, I fully expected to see my data grid get populated but the == comparison failed on the second line of code above.

The debugger shows this:

QUESTION: why were there no compile or runtime errors? (same question another way: what is actually being compared such that the == operator outputs FALSE?)

enter image description here

Froma answered 25/4, 2011 at 18:48 Comment(0)
I
4

Cast the Tag to string first. In the default implementation on object, == compares references. As the Tag property is of type object, it is using the lowest common == operator between object and string, which is the object implementation. By casting Tag to string, the implementation on string is used, which is a value comparision.

Ingraft answered 25/4, 2011 at 18:53 Comment(2)
Minor detail: String comparison is optimized to do reference comparison first and then do value comparison.Wagonage
Added minor detail: That is due to string interning.Ingraft
F
4

Use Object.Equals(treeViewItemTag, "ViewForAMs") instead

Frawley answered 25/4, 2011 at 18:54 Comment(0)
U
2

If you look at the type of treeViewItemTag, you will see that the type is object, not string. So when you use ==, you are comparing the references of two objects. That will always return false in this case. If you use Equals() instead, or cast to a string, then it should work.

Uncivil answered 25/4, 2011 at 18:54 Comment(0)
A
1

Use Equals() to compare strings.

UPDATE: Or cast both to strings. An example from MSDN:

string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine((object)a == (object)b);

The first comparison returns true, but the second returns false (because it compares references, not strings).

Abstraction answered 25/4, 2011 at 18:51 Comment(4)
This is more of a Java approach. A comparison between two strings has the == operator overloaded to test for value equality.Hedgcock
slavik, usually you'd be right, but in this case you're wrong. the var is of type object {string}, not of type string. So, the overload doesn't work in this case.Luffa
@slavik262, I have to disagree. It's ok when both values are of the string type. But if one is a string and the other is an object, you'll end comparing references if you're comparing using ==. (And a warning from compiler which is easy to miss). This won't happen if you're calling String.Equals(). Also you can't specify comparison options with == operator.Abstraction
In which case you should cast the object to a string, avoiding ambiguity. Just my opinion, anyways.Hedgcock
P
1

The Tag in TreeViewItem property is an object, not a string. The == is comparing object references. To compare the string, you should do the comparison using ToString():

if (treeViewItemTag.ToString() == "ViewForAMs")

But you have to be sure contains a string or else the comparison will also fail.

Pagas answered 25/4, 2011 at 18:54 Comment(0)
H
0

'treeViewItem.Tag' is a reference to an Object. By default in C#, the == operator checks for reference equality, i.e., that the two objects are one and the same same in memory. String has the '==' operator overloaded to check for value equality, that is, if the strings contain the same contents. To use it though, you need to cast 'treeViewItem.Tag' to a string.

Hedgcock answered 25/4, 2011 at 18:55 Comment(0)
E
0

I am not fluent with WPF, but in a Winforms context, I would have said that Tag is of type Object.
The equality operator on Object compares references.

If you (or some other reader) might want to know why this still works in some cases:
When you built strings via means of StringBuilder or unmanaged functions, you do not get a so.called intern string. That means, that there is a way that you have two distinct string objects at runtime that have the same content.
Usually, Strings refer to the same instance, except when they are built at runtime like explained above. You can call String.Intern to get an intern reference of a string with the same content. Those are bound to be the same instance for the same content. There are situations where knowing this tiny detail can be a big help or eye-opener.

Esurient answered 25/4, 2011 at 18:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.