-1

Does ObjectCollection.Add(item) call item.Equals()? Got a CheckedListBox on a Form, and tried to add some items. But I found when CheckedListBox.Items.Add(item) was called, it would call item.Equals(). Also, I found item.GetHashCode() was called, too. Very confused about why did it happen. Code are as below.

List<Person> people = new List<Person>();//Person is a customer class for test.
people.Add(new Person() { Name = "张三", Id = "201411580572", Gender = "Male" });
people.Add(new Person() { Name = "李四", Id = "201411580573", Gender = "Male" });
people.Add(new Person() { Name = "王武", Id = "201411580574", Gender = "Male" });
people.Add(new Person() { Name = "赵柳", Id = "201411580575", Gender = "Male" });
people.Add(new Person() { Name = "张飞", Id = "201411580576", Gender = "Male" });
people.Add(new Person() { Name = "赵云", Id = "201411580577", Gender = "Male" });

cklTest.DisplayMember = "Name";//cklTest is a CheckedListBox.

people.ForEach(p => cklTest.Items.Add(p));

Edit:

callstack

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
ZelgiusLiu
  • 82
  • 5
  • How did you find out that equals was called? – preciousbetine Jan 28 '19 at 15:13
  • databinding likely calls those methods to determine what to display to the user. it shouldn't be a problem. – Daniel A. White Jan 28 '19 at 15:14
  • Why don't you just use AddRange() instead of ForEach method? – jdweng Jan 28 '19 at 15:18
  • @preciousbetine I override the `Equals()` of the test-class. And it throwed error at the method. – ZelgiusLiu Jan 28 '19 at 15:18
  • Could you check if the `Sorted` property of your CheckedListBox is set to true? – Kevin Gosse Jan 28 '19 at 15:20
  • @jdweng I used to try the `AddRange()` method but it throwed error, and I thought maybe `Add()` would work well. – ZelgiusLiu Jan 28 '19 at 15:21
  • 1
    The [source](https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ListBox.cs,0d4081dfd8f378bb,references) shows that it needs to find the insert-position if the `ListControl` is sorted – Tim Schmelter Jan 28 '19 at 15:22
  • @KevinGosse It is set false. – ZelgiusLiu Jan 28 '19 at 15:22
  • Alternatively, you can uncheck `Enable Just My Code` in the Visual Studio options (Tools -> Options -> Debugging), then put a breakpoint in your `Equals` method and check the callstack. This way we'll know exactly where it comes from – Kevin Gosse Jan 28 '19 at 15:24
  • @KevinGosse I put a picture in the question content. – ZelgiusLiu Jan 28 '19 at 15:30
  • So you are updating `CheckedListBox` items and confused as to why some [specific](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.checkedlistbox.objectcollection) to that control collection calls some methods. Why would you want to know this? I am just curious what possible problem is lying behind such findings.. – Sinatr Jan 28 '19 at 15:34
  • You tried this : cklTest.Items.AddRange(people); – jdweng Jan 28 '19 at 15:34
  • 1
    Can you try setting `FormattingEnabled` to false on your CheckedListBox? – Kevin Gosse Jan 28 '19 at 15:35
  • @jdweng I tried it at very beginning, and it also called the `Equals()` method. – ZelgiusLiu Jan 28 '19 at 15:39
  • @KevinGosse Amazing, it now will not call the `Equals()` method. Thank you so much. So, it will call these methods id this property is set true? – ZelgiusLiu Jan 28 '19 at 15:43
  • Gonna write a short explanation – Kevin Gosse Jan 28 '19 at 15:43
  • I don't understand why this question got 3 times downvoted and is going to be be closed because it "must include desired behaviour...". OP noticed that his `Equals` is called when he adds items to a `CheckedListBox`. He wants to understand it and the answer isn't obvious(especially because [`Sorted`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.listbox.sorted?view=netframework-4.7.2#System_Windows_Forms_ListBox_Sorted) is `false`), so doesn't deserve downvotes, imo. The desired behavior is obviously that `Equals` is _not_ called. – Tim Schmelter Jan 28 '19 at 15:50
  • @Sinatr Well, in this case,for example, the `Equals()` method was very simple, `return Id==(obj as Person).Id;`. And it throwed `NullReferenceException`. So, if I know when and why it calls this method, I can get the code optimized to avoid this. – ZelgiusLiu Jan 28 '19 at 15:50
  • @ZelgiusLiu, that problem is [much easier to solve](https://stackoverflow.com/q/567642/1997232), simply fix your implementation. For any method receiving `object` parameter you have to expect a failed cast. – Sinatr Jan 28 '19 at 15:55

1 Answers1

2

Your callstack shows that the call comes from Formatter.FormatObject which in turn calls Formatter.IsNullData.

The code of IsNullData is:

public static bool IsNullData(object value, object dataSourceNullValue) {
    return value == null ||
           value == System.DBNull.Value ||
           Object.Equals(value, NullData(value.GetType(), dataSourceNullValue));
}

We see the call to Object.Equals to check if your object is equal to dataSourceNullValue (a custom value to represent null data). Interestingly, in this context dataSourceNullValue is DBNull.Value, therefore the check is redundant with the one above. But nothing you can do about that.

In case you don't want Equals to be called on this codepath, you can workaround by setting FormattingEnabled to false. This will cause the CheckedListBox to use an alternative way to format your object:

if (!formattingEnabled) {

    // Microsoft gave his blessing to this RTM breaking change
    if (item == null) {
        return String.Empty;
    }

    item = FilterItemOnProperty(item, displayMember.BindingField);
    return (item != null) ? Convert.ToString(item, CultureInfo.CurrentCulture) : "";
}
Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94