{"action":"created","issue":{"url":"https://api.github.com/repos/nunit/nunit/issues/1484","repository_url":"https://api.github.com/repos/nunit/nunit","labels_url":"https://api.github.com/repos/nunit/nunit/issues/1484/labels{/name}","comments_url":"https://api.github.com/repos/nunit/nunit/issues/1484/comments","events_url":"https://api.github.com/repos/nunit/nunit/issues/1484/events","html_url":"https://github.com/nunit/nunit/issues/1484","id":153657451,"number":1484,"title":"Comparing Equality using IEquatable<T> Should Use Most Specific Method","user":{"login":"lundmikkel","id":1230950,"avatar_url":"https://avatars.githubusercontent.com/u/1230950?v=3","gravatar_id":"","url":"https://api.github.com/users/lundmikkel","html_url":"https://github.com/lundmikkel","followers_url":"https://api.github.com/users/lundmikkel/followers","following_url":"https://api.github.com/users/lundmikkel/following{/other_user}","gists_url":"https://api.github.com/users/lundmikkel/gists{/gist_id}","starred_url":"https://api.github.com/users/lundmikkel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lundmikkel/subscriptions","organizations_url":"https://api.github.com/users/lundmikkel/orgs","repos_url":"https://api.github.com/users/lundmikkel/repos","events_url":"https://api.github.com/users/lundmikkel/events{/privacy}","received_events_url":"https://api.github.com/users/lundmikkel/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/nunit/nunit/labels/is:bug","name":"is:bug","color":"fc2929"},{"url":"https://api.github.com/repos/nunit/nunit/labels/pri:normal","name":"pri:normal","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/nunit/nunit/milestones/21","html_url":"https://github.com/nunit/nunit/milestones/Backlog","labels_url":"https://api.github.com/repos/nunit/nunit/milestones/21/labels","id":1444615,"number":21,"title":"Backlog","description":"This pseudo-milestone contains all items accepted for implementation but not assigned to a specific milestone. Developers should give priority to work on the current milestone, but may also chose items from the backlog to work on.","creator":{"login":"CharliePoole","id":2678661,"avatar_url":"https://avatars.githubusercontent.com/u/2678661?v=3","gravatar_id":"","url":"https://api.github.com/users/CharliePoole","html_url":"https://github.com/CharliePoole","followers_url":"https://api.github.com/users/CharliePoole/followers","following_url":"https://api.github.com/users/CharliePoole/following{/other_user}","gists_url":"https://api.github.com/users/CharliePoole/gists{/gist_id}","starred_url":"https://api.github.com/users/CharliePoole/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CharliePoole/subscriptions","organizations_url":"https://api.github.com/users/CharliePoole/orgs","repos_url":"https://api.github.com/users/CharliePoole/repos","events_url":"https://api.github.com/users/CharliePoole/events{/privacy}","received_events_url":"https://api.github.com/users/CharliePoole/received_events","type":"User","site_admin":false},"open_issues":146,"closed_issues":0,"state":"open","created_at":"2015-12-04T17:34:57Z","updated_at":"2016-06-03T06:41:04Z","due_on":"2020-12-31T08:00:00Z","closed_at":null},"comments":2,"created_at":"2016-05-08T13:59:50Z","updated_at":"2016-06-03T22:17:14Z","closed_at":null,"body":"Consider this example:\r\n```C#\r\npublic class EquatableObject : IEquatable<EquatableObject>\r\n{\r\n    public int SomeProperty { get; set; }\r\n    public bool Equals(EquatableObject other)\r\n    {\r\n        if (other == null)\r\n            return false;\r\n\r\n        return SomeProperty == other.SomeProperty;\r\n    }\r\n}\r\n\r\npublic class InheritingEquatableObject : EquatableObject, IEquatable<InheritingEquatableObject>\r\n{\r\n    public int OtherProperty { get; set; }\r\n    public bool Equals(InheritingEquatableObject other)\r\n    {\r\n        if (other == null)\r\n            return false;\r\n\r\n        return OtherProperty == other.OtherProperty && Equals((EquatableObject) other);\r\n    }\r\n}\r\n```\r\nThe following test currently fails:\r\n```C#\r\n[Test]\r\npublic void InheritingAndOverridingIEquatable()\r\n{\r\n    var obj1 = new InheritingEquatableObject { SomeProperty = 1, OtherProperty = 2 };\r\n    var obj2 = new InheritingEquatableObject { SomeProperty = 1, OtherProperty = 2 };\r\n    var obj3 = new InheritingEquatableObject { SomeProperty = 1, OtherProperty = 3 };\r\n    var obj4 = new InheritingEquatableObject { SomeProperty = 4, OtherProperty = 2 };\r\n\r\n    Assert.That(obj1, Is.EqualTo(obj2));\r\n    Assert.That(obj1, Is.Not.EqualTo(obj3)); // <-- Fails\r\n    Assert.That(obj1, Is.Not.EqualTo(obj4));\r\n}\r\n```\r\nThe second test fails, because the `EquatableObject`'s `Equals()` is used. It should be `InheritingEquatableObject`'s `Equals()` instead.\r\n\r\nThis is because [`NUnitEqualityComparer.FirstImplementsIEquatableOfSecond()`](https://github.com/nunit/nunit/blob/6f5c24f0a46d152a1fbffd907941e7e44c0058d7/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs#L250-257)  just returns the first usable method from the list generated by [`NUnitEqualityComparer.GetEquatableGenericArguments()`](https://github.com/nunit/nunit/blob/6f5c24f0a46d152a1fbffd907941e7e44c0058d7/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs#L259-275):\r\n```C#\r\nivate static MethodInfo FirstImplementsIEquatableOfSecond(Type first, Type second)\r\n{\r\n    var equatableGenericArguments = GetEquatableGenericArguments(first);\r\n    foreach (var xEquatableArgument in equatableGenericArguments)\r\n        if (xEquatableArgument.Key.IsAssignableFrom(second))\r\n            return xEquatableArgument.Value;\r\n\r\n    return null;\r\n}\r\n```\r\nThe result from `GetEquatableGenericArguments()` should somehow be sorted, or `FirstImplementsIEquatableOfSecond()` should return the best match, not just the first. The second approach seems to make most sense."},"comment":{"url":"https://api.github.com/repos/nunit/nunit/issues/comments/223707982","html_url":"https://github.com/nunit/nunit/issues/1484#issuecomment-223707982","issue_url":"https://api.github.com/repos/nunit/nunit/issues/1484","id":223707982,"user":{"login":"lundmikkel","id":1230950,"avatar_url":"https://avatars.githubusercontent.com/u/1230950?v=3","gravatar_id":"","url":"https://api.github.com/users/lundmikkel","html_url":"https://github.com/lundmikkel","followers_url":"https://api.github.com/users/lundmikkel/followers","following_url":"https://api.github.com/users/lundmikkel/following{/other_user}","gists_url":"https://api.github.com/users/lundmikkel/gists{/gist_id}","starred_url":"https://api.github.com/users/lundmikkel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lundmikkel/subscriptions","organizations_url":"https://api.github.com/users/lundmikkel/orgs","repos_url":"https://api.github.com/users/lundmikkel/repos","events_url":"https://api.github.com/users/lundmikkel/events{/privacy}","received_events_url":"https://api.github.com/users/lundmikkel/received_events","type":"User","site_admin":false},"created_at":"2016-06-03T22:17:14Z","updated_at":"2016-06-03T22:17:14Z","body":"Btw, is it okay to use LINQ here? There is a simple filter that could be done with `Enumerable.Where()`, and [`GetEquatableGenericArguments()`](https://github.com/lundmikkel/nunit/blob/e4cbfe6b870c092b69a8431fe2b898fe5bfacf70/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs#L264-265) even seems to have a comment about a previous solution that seems easily solvable with LINQ."}}
{"actor":{"display_login":"lundmikkel"}}