22

In the C# Language Specification Version 4, 1.6.7.5 Operators is information about List<T> operators: == and !=. But I can't find such operators defined in List<T>? Am I missing something?

Sample code from 1.6.7.5 Operators:

List<int> a = new List<int>();
a.Add(1);
a.Add(2);
List<int> b = new List<int>();
b.Add(1);
b.Add(2);
Console.WriteLine(a == b); // Outputs "True" => here I get False as well
b.Add(3);
Console.WriteLine(a == b); // Outputs "False"
Daniel Dušek
  • 13,683
  • 5
  • 36
  • 51

2 Answers2

22

List<T> is a reference type which does not overload operator==. Therefore, it uses the default reference equality semantics. You seem to be under the impression that it overrides operator== to provide value semantics, but it does not. a will equal b when a and b both refer to the same List<T> instance.

EDIT: So I looked at the spec myself. It says:

The List class declares two operators, operator == and operator !=, and thus gives new meaning to expressions that apply those operators to List instances. Specifically, the operators define equality of two List instances as comparing each of the contained objects using their Equals methods. The following example uses the == operator to compare two List instances.

Honestly... I have no clue what they're talking about, but this does not appear to be correct. As far as I can tell after running a few tests the List<T> class uses reference equality. Good question.

EDIT2: Decompiled List<T>, no operator== and/or operator!= overload. The spec appears to be completely incorrect in this case.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • 1
    The language spec says otherwise: "The List class declares two operators, operator == and operator !=, and thus gives new meaning to expressions that apply those operators to List instances. Specifically, the operators define equality of two List instances as comparing each of the contained objects using their Equals methods." – Sergey Kalinichenko Aug 07 '12 at 19:22
  • @dasblinkenlight: You're right, I'm reading it now. Trying to make sense of it... – Ed S. Aug 07 '12 at 19:22
  • @DanielDusek: Yes, I just added that to my post. It appears to be incorrect. Reality is not in line with the spec. – Ed S. Aug 07 '12 at 19:25
  • @JamesMichaelHare: Same here (had to dig around for a working version of reflector...). It appears that the spec is simply wrong on this point. – Ed S. Aug 07 '12 at 19:27
  • Yes, my *thought* is that the spec there was trying to illustrate and picked a bad example. That point of the spec, though, isn't intended to say that `List` must support those operators, it was just a wrong example of one that supposedly does... – James Michael Hare Aug 07 '12 at 19:30
  • @JamesMichaelHare: Agreed, just too bad that they chose a type for the example which made it completely incorrect. Even the same code is wrong! – Ed S. Aug 07 '12 at 19:33
  • @JamesMichaelHare you are correct. Look at the location where you all are reading. Anyway the specs are not the place to learn about List - MSDN is for that. The specs are for the building blocks of the C# language. **List is not one of it's building blocks :)** – Jony Adamit Aug 07 '12 at 19:34
  • @JonyAdamnit...: Well, ok, but I hardly think that's an excuse for the spec to be *blatantly incorrect*. – Ed S. Aug 07 '12 at 19:35
  • @JonyAdamnit... True, very true. Still, an unfortunate example. – James Michael Hare Aug 07 '12 at 19:35
  • @EdS. I think the thing that surprises me more is `List` has been around since .NET 2.0, kinda odd that they haven't found this (or at least haven't corrected it). – James Michael Hare Aug 07 '12 at 19:36
  • If you look at the C# 1.2 specification you will see something very similar. List didn't exist at the time of it's writing. – Jony Adamit Aug 07 '12 at 19:40
  • @EdS. The spec is correct (although confusing). See my answer below. – Dylan Meador Aug 07 '12 at 19:41
  • @Dylan: Ah, nice catch! I didn't consider this may be a fictional class used only for the sake of demonstration. +1 – Ed S. Aug 07 '12 at 19:49
17

The spec is indeed correct, although confusing. The spec defines a class called List (poor naming choice).

The following table shows a generic class called List, which implements a growable list of objects. The class contains several examples of the most common kinds of function members.

This class can be seen in the spec at section 1.6.7. The Equals operator is overloaded and matches the output explained above. Perhaps a better name should have been chosen for that class.

static bool Equals(List<T> a, List<T> b) {
    if (a == null) return b == null;
    if (b == null || a.count != b.count) return false;
    for (int i = 0; i < a.count; i++) {
        if (!object.Equals(a.items[i], b.items[i])) {
            return false;
        }
    }
  return true;
}
Dylan Meador
  • 2,381
  • 1
  • 19
  • 32