C# List merging without repeating - c#

My question is at the end of the following code in comments:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class MyObj
{
int m_id;
public MyObj(int id)
{
this.m_id = id;
}
public int GetId()
{
return this.m_id;
}
}
class Program
{
static void Main(string[] args)
{
var m0 = new MyObj(0);
var m1 = new MyObj(1);
var m2 = new MyObj(2);
var m3 = new MyObj(3);
var m4 = new MyObj(4);
List<MyObj> refList1 = new List<MyObj>()
{
m0, m1, m2, m3
};
List<MyObj> refList2 = new List<MyObj>()
{
m1, m2, m3, m4
};
//How to merge refList2 into refList1 without id repeating,
//so refList1 must be [m0, m1, m2, m3, m4]
}
}
}

You would do this using LINQ, with:
var resultList = refList1.Union(refList2).ToList();
However, this requires either that MyObj implements IEquatable<MyObj>, or the other overload of Union is used which takes an IEqualityComparer<T> parameter.
The first solution would need this change:
class MyObj : IEquatable<MyObj>
{
int m_id;
public MyObj(int id)
{
this.m_id = id;
}
public int GetId()
{
return this.m_id;
}
public bool Equals(MyObj other)
{
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return other.m_id == this.m_id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != typeof(MyObj)) {
return false;
}
return Equals((MyObj)obj);
}
public override int GetHashCode()
{
return this.m_id;
}
}
The second solution would go like:
class MyComparer : IEqualityComparer<MyObj>
{
public bool Equals(MyObj x, MyObj y)
{
return x.GetId() == y.GetId();
}
public int GetHashCode(MyObj obj)
{
return obj.GetId();
}
}
var resultList = refList1.Union(refList2, new MyComparer()).ToList();
and would not require changes to class MyObj.

You can use Union
Have a look here.

Use the Union Extension method.
var merged = refList2.Union(refList1).ToList();
And define the Equals/Hashcode methods. Once you do this it will automatically remove the duplicates.
class MyObj{
/*your stuff*/
public override bool Equals(object obj)
{
var r_list= obj as MyObj;
if(r_list == null) return false;
return this._m_id==r_list.m_id;
}
public override int GetHashCode()
{
return m_id;
}
}

refList1 = refList1.Union(refList2).Distinct.ToList();

Related

How to compare two dictionaries by value, even if the key or value are reference types?

I want to compare two Dictionary<SomeClass, List<AnotherClass>>. The dictionaries should be compared regardless of KeyValuePairs order. In the comments, ordering the values and then using SequenceEquals was suggested, but I am not sure how to Sort a dictionary (also, even sorting the lists could help, it's not possible as far as I understand because the generic type of the list is not guaranteed to be IComparable).
When I try to use the Equals method, I always get false since it checks whether the Lists are reference equals. I want it to check if the Lists are value equals. How to accomplish that?
So for example, let's say I have the following dictionaries:
var dictionary1 = new Dictionary<Day, List<WorkSession>>
{
{ Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } },
{ Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
{ Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } }
};
var dictionary2 = new Dictionary<Day, List<WorkSession>>
{
{ Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } },
{ Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
{ Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } }
};
WorkSession:
class WorkSession : IEquatable<WorkSession>
{
public string Entrance { get; private set; }
public string Exit { get; private set; }
public WorkSession(string entrance, string exit)
{
Entrance = entrance;
Exit = exit;
}
public override bool Equals(object obj)
{
return Equals(obj as WorkSession);
}
public bool Equals(WorkSession other)
{
return other != null &&
Entrance == other.Entrance &&
Exit == other.Exit;
}
public override int GetHashCode()
{
var hashCode = 1257807568;
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Entrance);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Exit);
return hashCode;
}
public static bool operator ==(WorkSession session1, WorkSession session2)
{
return EqualityComparer<WorkSession>.Default.Equals(session1, session2);
}
public static bool operator !=(WorkSession session1, WorkSession session2)
{
return !(session1 == session2);
}
}
I want two compare these dictionaries, and the result should be True. How can I accomplish that?
A possible solution is below. The equality checks are slightly tightened up compared to some of the other answers. For examples some null checks are added, and the values are checked in a different way (basically not just checking that the Values are the same but that they are the same for a given key).
Also, when comparing the lists, the data is sorted by all of the properties of WorkSession - just in case that two different WorkSession values have the same hash code. A better long term solution would be for WorkSession to implement IComparable.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace MattConsole
{
class Program
{
static void Main(string[] args)
{
var x = new Dictionary<Day, List<WorkSession>>
{
{ Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } },
{ Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
{ Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } }
};
var y = new Dictionary<Day, List<WorkSession>>
{
{ Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } },
{ Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
{ Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } }
};
var w = new MyCustomComparer();
var shouldBeTrue = w.Equals(x, y);
Console.WriteLine(shouldBeTrue);
x[Day.Wednesday] = new List<WorkSession>() { new WorkSession("10:00", "00:00") };
x[Day.Thursday] = new List<WorkSession>() { new WorkSession("10:01", "00:01") };
y[Day.Thursday] = new List<WorkSession>() { new WorkSession("10:00", "00:00") };
y[Day.Wednesday] = new List<WorkSession>() { new WorkSession("10:01", "00:01") };
var shouldBeFalse = w.Equals(x, y);
Console.WriteLine(shouldBeFalse);
Console.ReadLine();
}
}
public class MyCustomComparer : IEqualityComparer<Dictionary<Day, List<WorkSession>>>
{
public bool Equals(Dictionary<Day, List<WorkSession>> x, Dictionary<Day, List<WorkSession>> y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
if (ReferenceEquals(y, null))
return false;
if (x.Count != y.Count)
return false;
if (!x.Keys.OrderBy(z => z).SequenceEqual(y.Keys.OrderBy(z => z)))
return false;
foreach (var kvp in x)
{
List<WorkSession> matching;
if (y.TryGetValue(kvp.Key, out matching))
{
if (ReferenceEquals(matching, null))
return ReferenceEquals(kvp.Value, null);
if (ReferenceEquals(kvp.Value, null))
return false;
// ordering by hash code is not strictly necessary
if (
!matching.OrderBy(z => z.GetHashCode())
.ThenBy(z => z.Entrance).ThenBy(z => z.Exit)
.SequenceEqual(
kvp.Value.OrderBy(z => z.GetHashCode())
.ThenBy(z => z.Entrance).ThenBy(z => z.Exit)))
return false;
}
else
return false;
}
return true;
}
public int GetHashCode(Dictionary<Day, List<WorkSession>> obj)
{
throw new NotImplementedException();
}
}
public class WorkSession : IEquatable<WorkSession>
{
public string Entrance { get; private set; }
public string Exit { get; private set; }
public WorkSession(string entrance, string exit)
{
Entrance = entrance;
Exit = exit;
}
public override bool Equals(object obj)
{
return Equals(obj as WorkSession);
}
public bool Equals(WorkSession other)
{
return other != null &&
Entrance == other.Entrance &&
Exit == other.Exit;
}
public override int GetHashCode()
{
var hashCode = 1257807568;
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Entrance);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Exit);
return hashCode;
}
public static bool operator ==(WorkSession session1, WorkSession session2)
{
return EqualityComparer<WorkSession>.Default.Equals(session1, session2);
}
public static bool operator !=(WorkSession session1, WorkSession session2)
{
return !(session1 == session2);
}
}
}
Here is something crude that works that might get you started. There will be some edge cases you need to think about and adjust code accordingly.
class Program
{
static void Main(string[] args)
{
var x = new Dictionary<SomeClass, List<AnotherClass>>();
var y = new Dictionary<SomeClass, List<AnotherClass>>();
x.Add(new SomeClass { SomeNumericProperty = 1 }, new List<AnotherClass> { new AnotherClass { SomeStringProperty = "1" } });
y.Add(new SomeClass { SomeNumericProperty = 1 }, new List<AnotherClass> { new AnotherClass { SomeStringProperty = "1" } });
var w = new MyCustomComparer();
var z = w.Equals(x, y);
}
}
public class MyCustomComparer : IEqualityComparer<Dictionary<SomeClass, List<AnotherClass>>>
{
public bool Equals(Dictionary<SomeClass, List<AnotherClass>> x, Dictionary<SomeClass, List<AnotherClass>> y)
{
var keysAreEqual = x.Keys.OrderBy(o => o.GetHashCode()).SequenceEqual(y.Keys.OrderBy(o => o.GetHashCode()));
var valuesAreEqual = x.SelectMany(o => o.Value).OrderBy(o => o.GetHashCode()).SequenceEqual(y.SelectMany(o => o.Value).OrderBy(o => o.GetHashCode()));
return keysAreEqual && valuesAreEqual;
}
public int GetHashCode(Dictionary<SomeClass, List<AnotherClass>> obj)
{
throw new NotImplementedException();
}
}
public class AnotherClass
{
protected bool Equals(AnotherClass other)
{
return string.Equals(SomeStringProperty, other.SomeStringProperty);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((AnotherClass)obj);
}
public override int GetHashCode()
{
int hash = 13;
hash = (hash * 7) + SomeStringProperty.GetHashCode();
return hash;
}
public string SomeStringProperty { get; set; }
}
public class SomeClass
{
public int SomeNumericProperty { get; set; }
protected bool Equals(SomeClass other)
{
return SomeNumericProperty == other.SomeNumericProperty;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((SomeClass)obj);
}
public override int GetHashCode()
{
int hash = 13;
hash = (hash * 7) + SomeNumericProperty.GetHashCode();
return hash;
}
}

Compare Items in two Lists and return non matching Items

So I have two Lists.
List<Farmer> CSVFarmer;
List<Farmer> Farmers;
CSVFarmer List gets its items from a method that will read a csv file.
Farmers List gets its items from a table in a sql database;
Now what I want to do is compare the two lists and return a list of non matching items;
For example if List CSVFarmer has:
FarmerName ContractNumber ContactNumber
John 2468 12345
Mike 13579 15790
And List Farmers has:
FarmerName ContractNumber ContactNumber
Mike 13579 15790
The list being returned should only have one item in it : Farmer John.
Farmer Class:
public class Farmer:INotifyPropertyChanged
{
int _id;
string _firstName;
string _farmerNo;
string _contactNumber;
public Farmer()
{
_firstName = string.Empty;
_farmerNo = string.Empty;
_contactNumber = string.Empty;
}
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged("Id");
}
}
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
public string FarmerNo
{
get { return _farmerNo; }
set
{
_farmerNo = value;
OnPropertyChanged("FarmerNo");
}
}
public string ContactNumber
{
get { return _contactNumber; }
set
{
_contactNumber = value;
OnPropertyChanged("ContactNumber");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged (string property)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
Ive tried this:
public class vmUserManagement
{
public List<Farmer> Farmer { get; set; }
public List<Farmer> CSVFarmers { get; set; }
public List<Farmer> Farmers { get; set; }
public vmUserManagement()
{
CSVFarmers = new List<Farmer>();
Farmers = new List<Farmer>();
Farmer = new List<Farmer>();
}
public List<Farmer> getAllFarmers()
{
Farmers = RepoDapper.getAllFarmers();
return Farmers;
}
public List<Farmer> CSVImportFarmer()
{
OpenFileDialog openFile = new OpenFileDialog();
openFile.DefaultExt = ".csv";
openFile.Filter = "(.csv) | *.csv";
var browseFile = openFile.ShowDialog();
if (browseFile == true)
{
string FilePath = openFile.FileName;
List<Farmer> values = File.ReadAllLines(FilePath).Select(v => FromFarmerCsv(v)).ToList();
CSVFarmers = values;
}
return CSVFarmers;
}
public static Farmer FromFarmerCsv(string csvLine)
{
string[] values = csvLine.Split(',');
Farmer farmer = new Farmer();
farmer.FirstName = values[0];
farmer.FarmerNo = values[1];
farmer.ContactNumber = values[2];
return farmer;
}
public List<Farmer> validateFarmerList()
{
foreach (var a in CSVFarmers)
{
foreach (var b in Farmers)
{
if (a != b)
{
Farmer.Add(a);
}
}
}
return Farmer;
}
}
The problem I'm having is that I will end up with two entries in List Farmer. Both for Farmer John and Farmer Mike. When I should only be getting a List containing Farmer John. Why is that?
I've also tried using Except:
public List<Farmer> validateFarmerList()
{
Farmer = CSVFarmers.Except(Farmers).ToList();
return Farmer;
}
But I still get two items in my Farmer List (Farmer John and Mike) instead of one.
Am I missing something? Any help will be much appreciated.
You have't overridden Equals and GethashCode in your Farmer class. That's why (a != b) doesn't work and also Enumerable.Except fails for the same reason: only references are compared and both are different instances.
How should .NET know that the ContractNumber of the farmer is relevant to identify him? One wayy is to tell it by overriding Equals and GetHashCode:
public class Farmer : IEquatable<Farmer>
{
public string FarmerName { get; set; }
public string ContractNumber { get; set; }
// .... other properties etc
public bool Equals(Farmer other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(ContractNumber, other.ContractNumber);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Farmer) obj);
}
public override int GetHashCode()
{
return (ContractNumber != null ? ContractNumber.GetHashCode() : 0);
}
}
Now you can use Except:
Farmer = CSVFarmers.Except(Farmers).ToList();
2nd way is to implement a custom IEqualityComparer<Farmer>, f.e if you can't change the Farmer class itself or you don't want to change it's behaviour and just want a custom comparer:
public class FarmerContractComparer : IEqualityComparer<Farmer>
{
public bool Equals(Farmer x, Farmer y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(null, x) || ReferenceEquals(null, y)) return false;
return x.ContractNumber == y.ContractNumber;
}
public int GetHashCode(Farmer obj)
{
return (obj.ContractNumber != null ? obj.ContractNumber.GetHashCode() : 0);
}
}public class FarmerContractComparer : IEqualityComparer<Farmer>
{
public bool Equals(Farmer x, Farmer y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(null, x) || ReferenceEquals(null, y)) return false;
return x.ContractNumber == y.ContractNumber;
}
public int GetHashCode(Farmer obj)
{
return (obj.ContractNumber != null ? obj.ContractNumber.GetHashCode() : 0);
}
}
You can use this comparer in many LINQ methods, for example also in Enumerable.Except:
Farmer = CSVFarmers.Except(Farmers, new FarmerContractComparer()).ToList();
This approach has the advantage that you could provide different comparers for different tasks.
3rd approach: use LINQ and don't create a new class(less reusable and efficient but less work):
Farmer = CSVFarmers.Where(f => !Farmers.Any(f2 => f.ContractNumber == f2.ContractNumber)).ToList();
You will need to either create a class implementing IEqualityComparer<Farmer> and pass an instance of that as a second parameter to .Except() or implement IEquatable<Farmer> on your Farmer class.
The other answer already has a good implementation of the latter. If you always want farmers to be equal when their contract number is equal, use that one.
So if you want your Except work on contract numbers, but in other places you want other criteria, you need the first option:
class FarmerEqualWhenContractEqualComparer : IEqualityComparer<Farmer>
{
public bool Equals(Farmer x, Farmer y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the farmers' contracts are equal.
return x.ContractNumber == y.ContractNumber;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Farmer farmer)
{
//Check whether the object is null
if (Object.ReferenceEquals(product, null)) return 0;
//Get hash code for the Name field if it is not null.
return farmer.ContractNumber?.GetHashCode() ?? 0;
}
}
Then you can do:
var changedOrNew = CSVFarmers.Except(Farmers, new FarmerEqualWhenContractEqualComparer()).ToList();

Distinct with encapsulated equality

I have a collection of objects where I want to find distinct values based on several properties.
I could do this:
var distinct = myValues.GroupBy(p => new { A = p.P1, B = p.P2 });
But I want to encapsulate the equality sementics. Something like this:
public interface IKey<T>
{
bool KeyEquals(T other);
}
public class MyClass : IKey<MyClass>
{
public string P1 { get; set; }
public string P2 { get; set; }
public bool KeyEquals(MyClass other)
{
if(object.ReferenceEquals(this, other)
return true;
if(other == null)
return false;
return this.P1 == other.P1 && this.P2 == other.P2;
}
}
Is there an O(N) way to get distinct values using my KeyEquals function?
If you can't change MyClass, you can implement an IEqualityComparer:
class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass m1, MyClass m2)
{
return m1.KeyEquals(m2);
}
public int GetHashCode(MyClass m)
{
return (m.P1.GetHashCode() *23 ) + (m.P2.GetHashCode() * 17);
}
}
And pass it to GroupBy
var distinct = myValues.GroupBy(p => p, new MyClassComparer());

Creating a IEqualityComparer<IEnumerable<T>>

I'm using xUnit and it doesn't have a way to determine if 2 IEnumerable<T> are equal if T is custom type.
I've tried using LINQ SequenceEqual but again as the instances of T are different this returns false;
Here is a basic test with a non-working IEqualityComparer
[Fact]
public void FactMethodName()
{
var one = new[] { new KeywordSchedule() { Id = 1 } };
var two = new[] { new KeywordSchedule() { Id = 1 } };
Assert.Equal(one, two, new KeywordScheduleComparer());
}
public class KeywordScheduleComparer : IEqualityComparer<IEnumerable<KeywordSchedule>>
{
public bool Equals(IEnumerable<KeywordSchedule> x, IEnumerable<KeywordSchedule> y)
{
return Object.ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y));
}
public int GetHashCode(IEnumerable<KeywordSchedule> obj)
{
if (obj == null)
return 0;
return unchecked(obj.Select(e => e.GetHashCode()).Aggregate(0, (a, b) => a + b)); // BAD
}
}
I'm using this in an integration test, so I insert data from a IEnumerable into a DB at the start, then call my SUT to retrieve data from DB and compare.
If you can help me get a collection comparison working I'd appreciate it!
I just verified that this works fine with xUnit.net 1.9.2:
public class MyClass
{
public int ID { get; set; }
public string Name { get; set; }
}
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass x, MyClass y)
{
return x.ID == y.ID;
}
public int GetHashCode(MyClass obj)
{
return obj.ID.GetHashCode();
}
}
public class ExampleTest
{
[Fact]
public void TestForEquality()
{
var obj1 = new MyClass { ID = 42, Name = "Brad" };
var obj2 = new MyClass { ID = 42, Name = "Joe" };
Assert.Equal(new[] { obj1 }, new[] { obj2 }, new MyClassComparer());
}
}
So I'm not 100% clear why you need the extra comparer. Just the single comparer should be sufficient.
Well, your implementation is pending. You implemented custom comparer for IEnumerable<KeywordSchedule> but forgot to implement the same for KeywordSchedule.
x.SequenceEqual Still uses Comparer<T>.Default so it goes for reference comaprison and hence result is false.
public class KScheduleComparer : IEqualityComparer<KeywordSchedule>
{
public bool Equals(KeywordSchedule x, KeywordSchedule y)
{
return x.Id == y.Id;
}
public int GetHashCode(KeywordSchedule obj)
{
return obj.GetHashCode();
}
}
Then modify your Equals method in KeywordScheduleComparer class as below
public class KeywordScheduleComparer : IEqualityComparer<IEnumerable<KeywordSchedule>>
{
public bool Equals(IEnumerable<KeywordSchedule> x, IEnumerable<KeywordSchedule> y)
{
return Object.ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y, new KScheduleComparer()));
}
public int GetHashCode(IEnumerable<KeywordSchedule> obj)
{
if (obj == null)
return 0;
return unchecked(obj.Select(e => e.GetHashCode()).Aggregate(0, (a, b) => a + b)); // BAD
}
}
You could do this more elegantly using FluentAssertions library. It has plenty assertion methods for collections.
public class MyClass
{
public int ID { get; set; }
public string Name { get; set; }
protected bool Equals(MyClass other)
{
return ID == other.ID;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((MyClass) obj);
}
public override int GetHashCode()
{
unchecked
{
return (ID*397) ^ (Name != null ? Name.GetHashCode() : 0);
}
}
}
public class ExampleTest
{
[Fact]
public void TestForEquality()
{
var obj1 = new MyClass { ID = 42, Name = "Rock" };
var obj2 = new MyClass { ID = 42, Name = "Paper" };
var obj3 = new MyClass { ID = 42, Name = "Scissors" };
var obj4 = new MyClass { ID = 42, Name = "Lizard" };
var list1 = new List<MyClass> {obj1, obj2};
list1.Should().BeEquivalentTo(obj3, obj4);
}
}

Linq Distinct does not function as per forum and Microsoft examples

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace UnitTest.Model
{
[TestFixture]
public class SampleEquatableObjectTest
{
[Test]
public void TwoIdenticalUsersComparedEqualTrue()
{
var user1 = new SampleObject { Id = 1, Name = "Test User" };
var user2 = new SampleObject { Id = 1, Name = "Test User" };
Assert.IsTrue(user1.Equals(user2));
}
[Test]
public void TwoDifferentUsersComparedEqualFalse()
{
var user1 = new SampleObject { Id = 1, Name = "Test User 1" };
var user2 = new SampleObject { Id = 2, Name = "Test User 2" };
Assert.IsFalse(user1.Equals(user2));
}
[Test]
public void CollectionOfUsersReturnsDistinctList()
{
var userList = new List<SampleObject>
{
new SampleObject {Id = 1, Name = "Test User"},
new SampleObject {Id = 1, Name = "Test User 1"},
new SampleObject {Id = 2, Name = "Test User 2"}
};
Assert.AreEqual(userList.Count, 3);
var result = userList.Distinct();
Assert.AreEqual(result.Count(), 2);
var multipleTest = (from r in result group r by new { r.Id } into multGroup where multGroup.Count() > 1 select multGroup.Key).Any();
Assert.IsFalse(multipleTest);
}
public class SampleObject : IEquatable<SampleObject>
{
public int Id { get; set; }
public string Name { get; set; }
public bool Equals(SampleObject other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(other, null) || ReferenceEquals(this, null))
return false;
return Id.Equals(other.Id);
}
}
}
}
The distinct method in this test case does not return a distinct list. The assert for count will fail. I looked at other similar questions and Microsoft examples but they look exactly like the code I have in the test. Any input?
You also need to override the GetHashCode() and Equals methods from the Object class. For more information see this corresponding FXCOP violation.
Then your tests will work like expected.
public class SampleObject : IEquatable<SampleObject>
{
public int Id { get; set; }
public string Name { get; set; }
public bool Equals(SampleObject other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(other, null) || ReferenceEquals(this, null))
return false;
return Id.Equals(other.Id);
}
public override int GetHashCode()
{
return Id;
}
public override bool Equals(object obj)
{
return Equals(obj as SampleObject);
}
}
You're implementing an interface without defining both members to the specification of the interface. Your code needs to look like this:
public bool Equals(SampleObject x, SampleObject y)
{
if (ReferenceEquals(x, y))
return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
return false;
return x.Id.Equals(y.Id);
}
public int GetHashCode(SampleObject obj)
{
public int GetHashCode(SampleObject obj)
{
if (Object.ReferenceEquals(obj, null)) return 0;
int hashId = obj.Id == null ? 0 : obj.Id.GetHashCode();
int hashName = obj.Name == null ? 0 : obj.Name.GetHashCode();
return hashId ^ hashName; // or what ever you want you hash to be, hashID would work just as well.
}
}

Categories

Resources