title: LINQ Except operator and object equality
body: <p>Here is an interesting issue I noticed when using the <code>Except</code> Operator:
  I have list of users from which I want to exclude some users:</p>
  
  <p>The list of users is coming from an XML file:</p>
  
  <p>
    
    
    
    
    
    
    
     </p>
  
  <p></p>
  
  <p>The code goes like this:</p>
  
  <pre><code>interface IUser
  {
       int ID { get; set; }
       string Name { get; set; }
  }
  
  class User: IUser
  {
  
      #region IUser Members
  
      public int ID
      {
          get;
          set;
      }
  
      public string Name
      {
          get;
          set;
      }
  
      #endregion
  
      public override string ToString()
      {
          return ID + ":" +Name;
      }
  
  
      public static IEnumerable&lt;IUser&gt; GetMatchingUsers(IEnumerable&lt;IUser&gt; users)
      {
           IEnumerable&lt;IUser&gt; localList = new List&lt;User&gt;
           {
              new User{ ID=4, Name="James"},
              new User{ ID=5, Name="Tom"}
  
           }.OfType&lt;IUser&gt;();
           var matches = from u in users
                         join lu in localList
                             on u.ID equals lu.ID
                         select u;
           return matches;
      }
  }
  
  class Program
  {
      static void Main(string[] args)
      {
          XDocument doc = XDocument.Load("Users.xml");
          IEnumerable&lt;IUser&gt; users = doc.Element("Users").Elements("User").Select
              (u =&gt; new User
                  { ID = (int)u.Attribute("id"),
                    Name = (string)u.Attribute("name")
                  }
              ).OfType&lt;IUser&gt;();       //still a query, objects have not been materialized
  
  
          var matches = User.GetMatchingUsers(users);
          var excludes = users.Except(matches);    // excludes should contain 6 users but here it contains 8 users
  
      }
  }
  </code></pre>
  
  <p>When I call <code>User.GetMatchingUsers(users)</code> I get 2 matches as expected.
  The issue is that when I call <code>users.Except(matches)</code> The matching users are not being excluded at all! I am expecting 6 users ut "excludes" contains all 8 users instead.</p>
  
  <p>Since all I'm doing in  <code>GetMatchingUsers(IEnumerable&lt;IUser&gt; users)</code> is taking the <code>IEnumerable&lt;IUser&gt;</code> and just returning
  the <code>IUsers</code> whose ID's match( 2 IUsers in this case), my understanding is that by default <code>Except</code> will use reference equality
  for comparing the objects to be excluded. Is this not how <code>Except</code> behaves?</p>
  
  <p>What is even more interesting is that if I materialize the objects using <code>.ToList()</code> and then get the matching users, and call <code>Except</code>,
  everything works as expected!</p>
  
  <p>Like so:</p>
  
  <pre><code>IEnumerable&lt;IUser&gt; users = doc.Element("Users").Elements("User").Select
              (u =&gt; new User
                  { ID = (int)u.Attribute("id"),
                    Name = (string)u.Attribute("name")
                  }
              ).OfType&lt;IUser&gt;().ToList();   //explicity materializing all objects by calling ToList()
  
  var matches = User.GetMatchingUsers(users);
  var excludes = users.Except(matches);   // excludes now contains 6 users as expected
  </code></pre>
  
  <p>I don't see why I should need to materialize objects for calling <code>Except</code> given that its defined on <code>IEnumerable&lt;T&gt;</code>?</p>
  
  <p>Any suggesstions / insights would be much appreciated.</p>