为什么这个==比较失败了?(对我来说有点出乎意料)

7

背景:我正在为将我的WinForms应用程序转换为WPF做准备,进行原型设计。

我编写了非常简单的树形视图事件处理程序,代码如下:

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

而XAML代码如下:

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

当我运行它时,我完全期望看到我的数据网格被填充,但是在上面的第二行代码中,"=="比较失败了。 调试器显示了这个: 问题是:为什么没有编译或运行时错误?(换句话说,实际上在比较什么,使得"=="运算符输出FALSE?) enter image description here
7个回答

4

先将Tag转换为string类型。在的默认实现中,==比较的是引用。由于Tag属性的类型为object,它使用了objectstring之间最低公共的==运算符,即object的实现方式。通过将Tag强制转换为string,就可以使用string上的实现方式,也就是值比较。


小细节:字符串比较被优化为先进行引用比较,然后再进行值比较。 - Brian Rasmussen
添加了细节说明:这是由于字符串内部化。 - Femaref

4
请使用Object.Equals(treeViewItemTag, "ViewForAMs")代替。

2

如果你查看treeViewItemTag的类型,你会发现它的类型是对象,而不是字符串。因此当你使用==时,你比较的是两个对象的引用。在这种情况下,它将始终返回false。如果你使用Equals()方法或者将其强制转换为字符串,那么它应该正常工作。


1
使用Equals()方法来比较字符串。 更新:或将两个字符串强制转换为字符串。MSDN上的一个例子:
string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine((object)a == (object)b);

第一个比较返回 true,但第二个返回 false(因为它比较的是引用而不是字符串)。


这更像是一种 Java 的方法。两个字符串之间的比较已经重载了 == 运算符以测试值相等性。 - Matt Kline
斯拉维克,通常情况下你是对的,但在这种情况下你错了。该变量的类型为对象{字符串},而不是字符串类型。因此,在这种情况下重载是行不通的。 - invalidsyntax
@slavik262,我必须不同意。如果两个值都是字符串类型,那么使用“==”比较是可以的。但是如果一个是字符串,另一个是对象,那么使用“==”进行比较将会引用它们的地址(并且编译器会发出警告,易于忽略)。如果你使用String.Equals()方法,则不会发生这种情况。此外,你不能使用“==”操作符指定比较选项。 - Dmitry
在某些情况下,您应该将对象转换为字符串,以避免歧义。无论如何,这只是我的观点。 - Matt Kline

1
TreeViewItem的Tag属性是一个对象,而不是一个字符串。==运算符比较的是对象引用。要比较字符串,你应该使用ToString()进行比较:
if (treeViewItemTag.ToString() == "ViewForAMs")

但你必须确保包含一个字符串,否则比较也会失败。


0

'treeViewItem.Tag' 是一个对象的引用。在 C# 中,默认情况下,== 运算符检查引用相等性,即两个对象是否在内存中完全相同。String 类型重载了 '==' 运算符以检查值相等性,也就是说,如果字符串包含相同的内容,则它们相等。但要使用它,您需要将 'treeViewItem.Tag' 强制转换为字符串。


0

我对WPF不是很熟悉,但在Winforms环境中,我会说Tag是Object类型。
Object上的等号运算符比较引用。

如果您(或其他读者)想知道为什么在某些情况下仍然有效:
当您通过StringBuilder或非托管函数构建字符串时,您不会得到所谓的内部字符串。这意味着,在运行时,有一种方式可以拥有具有相同内容的两个不同的字符串对象。
通常,字符串引用相同的实例,除非像上面解释的那样在运行时构建它们。 您可以调用String.Intern来获取具有相同内容的字符串的内部引用。对于相同的内容,它们绑定为相同的实例。在某些情况下,了解这个微小的细节可能会有很大的帮助或启示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接