в чем основная причина сбоя этого == сравнения? (неожиданный результат для меня)

#c# #expression #typing

#c# #выражение #ввод

Вопрос:

Контекст: Я создаю прототип в prep для (возможно) преобразования моего приложения 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?)

введите описание изображения здесь

Ответ №1:

Сначала приведите Tag к string . В реализации по умолчанию на object , == сравнивает ссылки. Поскольку Tag свойство имеет тип object , оно использует наименьший общий == оператор между object и string , который является object реализацией. При приведении к Tag string используется реализация на string , которая является сравнением значений.

Комментарии:

1. Небольшая деталь: сравнение строк оптимизировано для того, чтобы сначала выполнять сравнение ссылок, а затем сравнивать значения.

2. Добавлена незначительная деталь: это связано с интернированием строки.

Ответ №2:

Используйте Object.Equals(treeViewItemTag, "ViewForAMs") вместо

Ответ №3:

Если вы посмотрите на тип treeViewItemTag, вы увидите, что тип — object, а не string. Итак, когда вы используете == , вы сравниваете ссылки на два объекта. В этом случае это всегда будет возвращать false. Если вы используете Equals () вместо этого или приводите к строке, то это должно сработать.

Ответ №4:

Тег в свойстве TreeViewItem является объектом, а не строкой. == сравнивает ссылки на объекты. Чтобы сравнить строку, вы должны выполнить сравнение с помощью toString():

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

Но вы должны быть уверены, что содержит строку, иначе сравнение также завершится неудачей.

Ответ №5:

Используйте 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 (потому что оно сравнивает ссылки, а не строки).

Комментарии:

1. Это больше похоже на подход Java. При сравнении двух строк оператор == перегружен для проверки равенства значений.

2. славик, обычно ты был бы прав, но в этом случае ты ошибаешься. переменная имеет тип object {string}, а не тип string. Итак, перегрузка в этом случае не работает.

3. @slavik262, я вынужден не согласиться. Это нормально, когда оба значения имеют строковый тип. Но если одно из них является строкой, а другое — объектом, вы закончите сравнение ссылок, если вы сравниваете с использованием == . (И предупреждение от компилятора, которое легко пропустить). Этого не произойдет, если вы вызываете String . Equals(). Также вы не можете указать параметры сравнения с помощью оператора == .

4. В этом случае вы должны преобразовать объект в строку, избегая двусмысленности. В любом случае, это просто мое мнение.

Ответ №6:

‘TreeViewItem.Тег’ — это ссылка на объект. По умолчанию в C # оператор == проверяет равенство ссылок, то есть, что два объекта являются одним и тем же в памяти. В строке перегружен оператор ‘==’ для проверки равенства значений, то есть, содержат ли строки одинаковое содержимое. Однако, чтобы использовать его, вам нужно привести ‘TreeViewItem.Добавляйте тег’ к строке.

Ответ №7:

Я не свободно владею WPF, но в контексте Winforms я бы сказал, что тег имеет тип Object .
Оператор равенства для объекта сравнивает ссылки.

Если вы (или какой-либо другой читатель), возможно, захотите узнать, почему это все еще работает в некоторых случаях:
Когда вы строите строки с помощью StringBuilder или неуправляемых функций, вы не получаете так называемую промежуточную строку. Это означает, что во время выполнения у вас есть два разных объекта string, которые имеют одинаковое содержимое.
Обычно строки ссылаются на один и тот же экземпляр, за исключением случаев, когда они создаются во время выполнения, как описано выше. Вы можете вызвать String .Intern для получения ссылки intern на строку с тем же содержимым. Это обязательно должен быть один и тот же экземпляр для одного и того же содержимого. Бывают ситуации, когда знание этой крошечной детали может оказать большую помощь или открыть глаза.