Bug 6373 - HashSet<T>.SetEquals () does not use specified EqualityComparer
Summary: HashSet<T>.SetEquals () does not use specified EqualityComparer
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System.Core ()
Version: 2.10.x
Hardware: All All
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-08-02 22:51 UTC by tome
Modified: 2012-08-15 16:29 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description tome 2012-08-02 22:51:12 UTC
HashSet<T>.SetEqual (IEnumerable<T> other) does not use specified EqualityComparer (given when created the HashSet<T>).
Think following test code;

public class MyFile
{
	public string Path { get; set; }
	public MyFile () {}
}

public class MyFileEqalityComparer : IEqualityComparer<MyFile>
{
	public bool Equals (MyFile x, MyFile y)
	{
		if (x == null && y == null)
			return true;
		else if (x == null || y == null)
			return false;
		return String.Equals (x.Path, y.Path);
	}

	public int GetHashCode (MyFile obj)
	{
		return (obj == null) ? 0 : obj.Path.GetHashCode ();
	}

	public MyFileEqualityComparer () {}
}

[Test]
public void MyFileEqualityComparerTest ()
{
	string path1 = "/private";
	string path2 = "/private/var";

	var myfile1 = new MyFile { Path = path1 };
	var myfile2 = new MyFile { Path = path2 };
	var yet_another_myfile1 = new MyFile { Path = path1 };
	var yet_another_myfile2 = new MyFile { Path = path2 };

	List<MyFile> list1 = new List<MyFile> { myfile1, myfile2 };
	List<MyFile> list2 = new List<MyFile> { yet_another_myfile1, yet_another_myfile2 };

	Assert.True (list1.SequenceEqual (list2, new MyFileEqalityComparer ())); // OK

	HashSet<MyFile> set1 = new HashSet<MyFile> (list1, new MyFileEqalityComparer ());

	Assert.True (set1.SetEquals (list2)); // oops!!! failed 
}

The first test; SequenceEqual () passes, but the second; SetEquals () does not.
Do you think the second should be passed as well?
Please don't bash about the MyFile's deffects neither GetHashCode() nor Equals ().
That is an instead of the NSUrl in MonoTouch library in my original code.

Anyway, I saw the implementation of SetEquals (),  there are (almost) always used to compare with the EqualityComparer<T>.Default.
following code is a snippet of the implementation from Mono library in System.Core/System.Collections.Generic/HashSet.cs.

public bool SetEquals (IEnumerable<T> other)
{
	if (other == null)
		throw new ArgumentNullException ("other");

	var other_set = ToSet (other); // almost always created the other's set with EqualityComparer<T>.Default

	if (count != other_set.Count)
		return false;

	foreach (var item in this)
		if (!other_set.Contains (item)) // and use the comparer of other's set here
			return false;

	return true;
}
Comment 1 Enrico Sada 2012-08-04 14:38:40 UTC
sent pull request https://github.com/mono/mono/pull/415 with fix + test
Comment 2 Miguel de Icaza [MSFT] 2012-08-15 16:29:59 UTC
Closing, patch was added