在第三方上实施自定义哈希码 class
Implement a custom hashcode on a third party class
我在来自第三方的 VisualStudio C# 项目中使用 class 行(无法访问源代码)
我的代码正在生成 hundreds/thousands 个包含重复项的行对象,我需要将它们存储在某种集合(List、HashSet)中以供进一步处理(在屏幕上绘制)。
Line class 具有类型为 Point 的 StartPoint 和 EndPoint 属性等。
出于我需要做的事情,线方向并不重要,如果起点和终点相同,则两个 Line 对象是相同的。
然而,我使用的 class 行为不同,两个 Line 对象被认为是唯一的,即使它们具有相同的 start/end 点。 (GetHashCode returns 不同的值)
问题是 - 如何为第三方实施自定义 IComparer 或 GetHashCode 例程 class 以便能够使用 HashSet 结构或 List.Distinct() 功能?
感谢 Ilian 和 Hasan,他们成功了
如果您不介意,请快速跟进问题:
我不确定是使用 List 还是 HashSet 来保存我的数据,所以我尝试了两者并对其进行了计时。结果显示一个比另一个慢几个数量级。对正在发生的事情有什么见解吗?
class LineComparer : IEqualityComparer<Line>
{
public bool Equals(Line l1, Line l2)
{
if (l1.EndPoint == l2.EndPoint && l1.StartPoint == l2.StartPoint) return true;
if (l1.EndPoint == l2.StartPoint && l1.StartPoint == l2.EndPoint) return true;
return false;
}
public int GetHashCode(Line line) => line.StartPoint.GetHashCode() ^ line.EndPoint.GetHashCode();
}
这是我的 HashSet 代码:
var timer = new Stopwatch();
timer.Start();
var result = new HashSet(new LineComparer());
GenerateAndStore20000Lines();
timer.Stop();
Ed.WriteMessage($"\n生成了 {result.Count} 行,哈希集时间:{timer.ElapsedMilliseconds}");
return 结果;
结果:
* 使用 HashSet 的时间:1302
* 使用 HashSet 的时间:1328
* 使用 HashSet 的时间:1314
* 使用 HashSet 的时间:1311
* 使用 HashSet 的时间:1303
带有列表的代码:
var timer = new 秒表();
timer.Start();
var result = new List();
GenerateAndStore20000Lines();
timer.Stop();
Ed.WriteMessage($"\n生成了 {result.Count} 行,使用列表的时间:{timer.ElapsedMilliseconds}");
return result.Distinct(new LineComparer());
结果:
- 生成了 20002 行,使用列表的时间:26
- 生成了 20002 行,使用列表的时间:11
- 生成了 20002 行,使用列表的时间:14
- 生成了 20002 行,使用列表的时间:12
- 生成了 20002 行,使用列表的时间:12
(抱歉格式不好,但这个界面让我抓狂...放弃)
使用 IEqualityComparer
的重载(您必须实现)。
参见 this HashSet
。
我想,你的意思是 Enumerable.Distinct
。使用 this.
我只是在扩展 @Ilian 答案。尝试尽可能多地发表评论,所以我相信最好让代码来说话:)
// Mock 3rd Party point
public class ThirdPartyPoint {
}
// Mock 3rd party line
public class ThirdPartyLine {
public ThirdPartyPoint StartPoint { get; set; }
public ThirdPartyPoint EndPoint { get; set; }
}
// This class implements IEqualityComparer<ThirdPartyLine>, which compares
// ThirdPartyLine's equality. THis class will be passed as a ctor arument to HashSet<T>
public class CompareLines : IEqualityComparer<ThirdPartyLine> {
public bool Equals(ThirdPartyLine x, ThirdPartyLine y) {
// Here check for the equality of the start and end points.
// I asuumed the following but do not know how the eaulity is implemented in your library.
return x.EndPoint == y.EndPoint && x.StartPoint == y.StartPoint;
}
public int GetHashCode(ThirdPartyLine obj) {
// Implement an algortihm which must return same hashcode for objects considered the same.
// I am not sure about the Point class hashcode but I am jsut assuming the following.
return obj.StartPoint.GetHashCode() ^ obj.EndPoint.GetHashCode();
}
}
private static void Main(string[] args) {
// Hashset to hold lines
var hashSet = new HashSet<ThirdPartyLine>(new Compare());
// start point
var starPoint = new ThirdPartyPoint();
// end point
var endPoint = new ThirdPartyPoint();
// Lines with same start and end points
var line1 = new ThirdPartyLine {
StartPoint = starPoint,
EndPoint = endPoint
};
var line2 = new ThirdPartyLine {
StartPoint = starPoint,
EndPoint = endPoint
};
// Check count first
hashSet.Add(line1);
var count = hashSet.Count;
// Check count second, still 1
hashSet.Add(line2);
count = hashSet.Count;
}
我在来自第三方的 VisualStudio C# 项目中使用 class 行(无法访问源代码) 我的代码正在生成 hundreds/thousands 个包含重复项的行对象,我需要将它们存储在某种集合(List、HashSet)中以供进一步处理(在屏幕上绘制)。 Line class 具有类型为 Point 的 StartPoint 和 EndPoint 属性等。 出于我需要做的事情,线方向并不重要,如果起点和终点相同,则两个 Line 对象是相同的。 然而,我使用的 class 行为不同,两个 Line 对象被认为是唯一的,即使它们具有相同的 start/end 点。 (GetHashCode returns 不同的值) 问题是 - 如何为第三方实施自定义 IComparer 或 GetHashCode 例程 class 以便能够使用 HashSet 结构或 List.Distinct() 功能?
感谢 Ilian 和 Hasan,他们成功了 如果您不介意,请快速跟进问题: 我不确定是使用 List 还是 HashSet 来保存我的数据,所以我尝试了两者并对其进行了计时。结果显示一个比另一个慢几个数量级。对正在发生的事情有什么见解吗?
class LineComparer : IEqualityComparer<Line>
{
public bool Equals(Line l1, Line l2)
{
if (l1.EndPoint == l2.EndPoint && l1.StartPoint == l2.StartPoint) return true;
if (l1.EndPoint == l2.StartPoint && l1.StartPoint == l2.EndPoint) return true;
return false;
}
public int GetHashCode(Line line) => line.StartPoint.GetHashCode() ^ line.EndPoint.GetHashCode();
}
这是我的 HashSet 代码:
var timer = new Stopwatch();
timer.Start();
var result = new HashSet(new LineComparer());
GenerateAndStore20000Lines();
timer.Stop(); Ed.WriteMessage($"\n生成了 {result.Count} 行,哈希集时间:{timer.ElapsedMilliseconds}");
return 结果;
结果: * 使用 HashSet 的时间:1302 * 使用 HashSet 的时间:1328 * 使用 HashSet 的时间:1314 * 使用 HashSet 的时间:1311 * 使用 HashSet 的时间:1303
带有列表的代码:
var timer = new 秒表(); timer.Start();
var result = new List();
GenerateAndStore20000Lines();
timer.Stop(); Ed.WriteMessage($"\n生成了 {result.Count} 行,使用列表的时间:{timer.ElapsedMilliseconds}");
return result.Distinct(new LineComparer());
结果:
- 生成了 20002 行,使用列表的时间:26
- 生成了 20002 行,使用列表的时间:11
- 生成了 20002 行,使用列表的时间:14
- 生成了 20002 行,使用列表的时间:12
- 生成了 20002 行,使用列表的时间:12
(抱歉格式不好,但这个界面让我抓狂...放弃)
使用 IEqualityComparer
的重载(您必须实现)。
参见 this HashSet
。
我想,你的意思是 Enumerable.Distinct
。使用 this.
我只是在扩展 @Ilian 答案。尝试尽可能多地发表评论,所以我相信最好让代码来说话:)
// Mock 3rd Party point
public class ThirdPartyPoint {
}
// Mock 3rd party line
public class ThirdPartyLine {
public ThirdPartyPoint StartPoint { get; set; }
public ThirdPartyPoint EndPoint { get; set; }
}
// This class implements IEqualityComparer<ThirdPartyLine>, which compares
// ThirdPartyLine's equality. THis class will be passed as a ctor arument to HashSet<T>
public class CompareLines : IEqualityComparer<ThirdPartyLine> {
public bool Equals(ThirdPartyLine x, ThirdPartyLine y) {
// Here check for the equality of the start and end points.
// I asuumed the following but do not know how the eaulity is implemented in your library.
return x.EndPoint == y.EndPoint && x.StartPoint == y.StartPoint;
}
public int GetHashCode(ThirdPartyLine obj) {
// Implement an algortihm which must return same hashcode for objects considered the same.
// I am not sure about the Point class hashcode but I am jsut assuming the following.
return obj.StartPoint.GetHashCode() ^ obj.EndPoint.GetHashCode();
}
}
private static void Main(string[] args) {
// Hashset to hold lines
var hashSet = new HashSet<ThirdPartyLine>(new Compare());
// start point
var starPoint = new ThirdPartyPoint();
// end point
var endPoint = new ThirdPartyPoint();
// Lines with same start and end points
var line1 = new ThirdPartyLine {
StartPoint = starPoint,
EndPoint = endPoint
};
var line2 = new ThirdPartyLine {
StartPoint = starPoint,
EndPoint = endPoint
};
// Check count first
hashSet.Add(line1);
var count = hashSet.Count;
// Check count second, still 1
hashSet.Add(line2);
count = hashSet.Count;
}