Unexpected behavior of LINQ Except()

Viewed 85

I have encountered a strange bahavior of LINQ Except method which I don't understand. I can totally rewrite my code differently so that it works, that is not my problem. I just want to understand why it fails as it is:

public void MyMethod(MyClass whatever, params object[] values){ // called with values = [ "mystr1", "mystr2", true, true ] 
  var valuesOfType = values.OfType<MyType>().ToList(); // valuesOfType is Empty List Count = 0
  values = values.Except(valuesOfType ).ToArray(); // values = [ "mystr1", "mystr2", true ] 
}

So last element of values is gone by applying Except() with an empty list! How is this possible? I reran in debugger immidiate window the line again, it was not trunkated to 2 elements. Self assignment to values is not a problem, I tried it with another variable, it still trunkates. What is happening here?

PS: MyType is just a simple type with one get property.

Although the question is already answered, here is a reproduceable console app, if somebody should want to see it for himself:

namespace ConsoleApp1
{
    using System;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            var para = new object[] {"str1", "str2", true, true};
            var temp = new TestClass(new Dummy1(), para);
        }

        public class TestClass
        {
            public TestClass(Dummy1 dummy1, params object[] values)
            {
                var valuesOfType = values.OfType<Dummy2>().ToList();
                values = values.Except(valuesOfType).ToArray();

                foreach (var value in values)
                {
                    Console.WriteLine(value);
                }
                
                Console.ReadKey();
            }
        }

        public class Dummy1
        {
        }

        public class Dummy2
        {
        }
    }
}
1 Answers

That's because LINQ Except produces a set difference, so duplicates are removed. From documentation:

This method returns those elements in first that don't appear in second. It doesn't return those elements in second that don't appear in first. Only unique elements are returned.

In your case you have two true values, so only one is returned.

Related