-1

I'm writing a console app using c# .NET 4.7.2. I have 2 lists of objects that I am trying to see if they are equal. I am using SequenceEqual to do this, but it is returning false when it should be returning true.

Here's my code:

List<Objects.PackageDetails> ExpectedResult1 = new List<Objects.PackageDetails>()
            {
                new Objects.PackageDetails{PackageName = "KittenService", PackageDependency = "CamelCaser"},
                new Objects.PackageDetails{PackageName = "CamelCaser", PackageDependency = ""}
            };

            List<Objects.PackageDetails> ExpectedResult = new List<Objects.PackageDetails>()
            {
                new Objects.PackageDetails{PackageName = "KittenService", PackageDependency = "CamelCaser"},
                new Objects.PackageDetails{PackageName = "CamelCaser", PackageDependency = ""}
            };

            var a = ExpectedResult1.SequenceEqual(ExpectedResult);

            Console.WriteLine(">" + ExpectedResult1[0].PackageName + "<");
            Console.WriteLine(">" + ExpectedResult[0].PackageName + "<");
            Console.WriteLine(">" + ExpectedResult1[0].PackageDependency + "<");
            Console.WriteLine(">" + ExpectedResult[0].PackageDependency + "<");

            Console.WriteLine(">" + ExpectedResult1[1].PackageName + "<");
            Console.WriteLine(">" + ExpectedResult[1].PackageName + "<");
            Console.WriteLine(">" + ExpectedResult1[1].PackageDependency + "<");
            Console.WriteLine(">" + ExpectedResult[1].PackageDependency + "<");

            if (ExpectedResult1[0].PackageName == ExpectedResult[0].PackageName)
            {
                Console.WriteLine("equal");
            }
            else
            {
                Console.WriteLine("not equal");
            }

            if (ExpectedResult1[1].PackageName == ExpectedResult[1].PackageName)
            {
                Console.WriteLine("equal");
            }
            else
            {
                Console.WriteLine("not equal");
            }

            if (ExpectedResult1[0].PackageDependency == ExpectedResult[0].PackageDependency)
            {
                Console.WriteLine("equal");
            }
            else
            {
                Console.WriteLine("not equal");
            }

            if (ExpectedResult1[1].PackageDependency == ExpectedResult[1].PackageDependency)
            {
                Console.WriteLine("equal");
            }
            else
            {
                Console.WriteLine("not equal");
            }
Console.Readline();

I am comparing the two lists to each other and when I hover over var a it says that it is false. But all of the display statements show that visibly the values are the same and also the if statements that compare the individual values show that they are all equal as well.

Will someone please give me an idea as to why SequenceEqual is saying the two lists are not equal but everything else I've done to determine if they are or not says they are equal? Thanks in advance.

EDIT: Here is my class declaration just in case it matters:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Objects
{
    public class PackageDetails
    {
        public string PackageName { get; set; }
        public string PackageDependency { get; set; }
    }
}
  • Where is the `PackageDetails` class? Have you either overridden `Equals` there or implemented `IEquatable`? – Tim Schmelter Feb 04 '19 at 17:36
  • @Rango it's in my solution, I don't think it really matters where it is though because from my post you can see I'm declaring the two lists using the same type, they should be equal. – Gharbad_The_Weak Feb 04 '19 at 17:37
  • @Gharbad_The_Weak the question is did you implement `IEquatable` or override `Equals` on your `PackageDetails` class? Because otherwise the comparison is on the reference, which will be false. – Rufus L Feb 04 '19 at 17:38
  • I just updated my post with my class declaration of `PackageDetails`. Can I get a little more detail on how exactly I need to override `Equals` to get this comparison to work? – Gharbad_The_Weak Feb 04 '19 at 17:40
  • @Gharbad_The_Weak You should override `Equals` method and add whatever logic you want to that determines if two of your classes are equal. For example, you could do a case-insensitive comparison of the `PackageName` and `PackageDependency` between the two classes being compared. If you search for "override equals c#" online, there are lots of examples. – Rufus L Feb 04 '19 at 17:43

1 Answers1

2

Equality isn't "looks the same"; for objects, equality defaults to is the same reference, which they won't be in this case (because each list separately creates separate objects, via new Objects.PackageDetails). If you want to customize equality, you need to override Equals (ideally also implementing IEquatable<T> for T the same type), and as soon as you do that you also need to correctly implement GetHashCode(). So: Does PackageDetails define custom equality? If not: this is exactly as I would expect.

One sneaky but code-efficient way to do this is to abuse value-tuples:

public override bool Equals(object obj) => Equals(obj as PackageDetails);
public bool Equals(PackageDetails obj) {
    if(obj == null) return false;
    return (PackageName, PackageDependency).Equals((obj.PackageName, obj.PackageDependency));
}
public override int GetHashCode() {
   return (PackageName, PackageDependency).GetHashCode();
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • thanks for the answer, can you provide an example of how to implement your concept? – Gharbad_The_Weak Feb 04 '19 at 17:42
  • @Gharbad_The_Weak press refresh in your browser... – Marc Gravell Feb 04 '19 at 17:42
  • Ok, I've changed my object definition to include your code and am implementing it like this: `var a = ExpectedResult1.Equals(ExpectedResult);` but it is still setting `a` as false. Am I using this wrong? – Gharbad_The_Weak Feb 04 '19 at 17:50
  • @Gharbad_The_Weak That is comparing equality between the two `List` objects, which again will use a reference comparison. If you want to compare the list *members* (and their order in the lists), use `var a = ExpectedResult1.SequenceEquals(ExpectedResult);`. If you just want to compare the items in the lists but don't care if they're in a different order from each other, you could do `var a = !ExpectedResults1.Except(ExpectedResult).Any() && ExpectedResults1.Count == ExpectedResult.Count;` – Rufus L Feb 04 '19 at 17:53
  • @MarcGravell ah, got it now, works like a charm. Sorry for the trouble in what seems like a very easy problem. I accepted your answer and tried to give you an up vote but my reputation is too low for it to show. Thanks! – Gharbad_The_Weak Feb 04 '19 at 17:57