在可变类型中实现IEquatable
我有一个代表外部物理测量设备的课程。 简化版本如下所示:
public class Device { public string Tag { get; set; } public int Address { get; set; } }
Tag
是用于识别设备的用户定义值。 Address
是适配器用于与设备通信的值。 如果两个Device
实例具有相同的Address
,则将使用相同的外部测量设备。
我想通过重写Equals
并实现IEquatable
来模仿代码中的行为(使用Contains
和Distinct
等方法):
public class Device : IEquatable { public string Tag { get; set; } public int Address { get; set; } public override bool Equals(object obj) { return Equals(obj as Device); } public bool Equals(Device other) { if (null == other) return false; if (ReferenceEquals(this, other)) return true; return Address.Equals(other.Address); } }
如您所见,我忽略了Equals
实现中的Tag
属性。
所以,我的问题是:我应该忽略Equals
实现中的Tag
属性吗? 这样做会让代码更难理解吗? 有没有更好的方法来做我想做的事情? 我需要Tag
属性,因为用户通常不会知道Address
,甚至Device
是否有Address
(在App.config文件中处理,并且用户将处理一个名为的接口) IDevice
没有Address
属性)。
更新:
谢谢大家的回复。
所以,我认为我应该使用自定义IEqualityComparer
。 如果我的真实代码看起来更像这样,您对如何操作有任何指导吗?
public interface IDevice { string Tag { get; set; } double TakeMeasurement(); } internal class Device : IDevice { public string Tag { get; set; } public int Address { get; set; } public double TakeMeasurement() { // Take a measurement at the device's address... } }
我应该检查IEqualityComparer
的设备类型吗?
public class DeviceEqualityComparer : IEqualityComparer { public bool Equals(IDevice x, IDevice y) { Contract.Requires(x != null); Contract.Requires(y != null); if ((x is Device) && (y is Device)) { return x.Address.Equals(y.Address); } else { return x.Equals(y); } } public int GetHashCode(IDevice obj) { Contract.Requires(obj != null); if (obj is Device) { return obj.Address.GetHashCode(); } else { return obj.GetHashCode(); } } }
是的,您目前的实施绝对令人困惑。 你所定义的平等显然不是设备平等的正确概念。
所以,我没有像你那样实现IEquatable
,而是定义了IEqualityComparer
,也许
class DeviceAddressEqualityComparer : IEqualityComparer { public bool Equals(Device x, Device y) { Contract.Requires(x != null); Contract.Requires(y != null); return x.Address.Equals(y.Address); } public int GetHashCode(Device obj) { Contract.Requires(obj != null); return obj.Address.GetHashCode(); } }
您可以将IEqualityComparer
实例传递给Contains
, Distinct
和依赖于相等的其他LINQ方法(例如, GroupBy
)。
首先,您忘记覆盖GetHashCode()
,因此您的代码已损坏。
只有当两个对象对于所有目的都是等效的时,IMO才应该重写Equals
。 对于某些目的,具有不同Tag
的对象看起来不同。
我根本不会在这些对象上重写Equals
。 我宁愿实现自定义比较器IEqualityComparer
并在适当的地方使用它。 大多数具有相等概念的方法都将IEqualityComparer
作为可选参数。
我不会禁止null
参数,但处理它们。 我还为参考平等增加了一个早期。
public class DeviceByAddressEqualityComparer : IEqualityComparer { public bool Equals(IDevice x, IDevice y) { if(x==y) return true; if(x==null||y==null) return false; return x.Address.Equals(y.Address); } public int GetHashCode(IDevice obj) { if(obj == null) return 0; else return obj.Address.GetHashCode(); } }
如果要检查类型,则取决于上下文。 当重写Equals
我通常检查是否x.GetType()==y.GetType()
,但由于你在这里使用了一个特殊用途的比较器,故意忽略了对象的一部分,我可能不会使类型部分身份。
我应该忽略Equals实现中的Tag属性吗?
不,我认为这是一个坏主意。
这样做会让代码更难理解吗?
绝对:一个新的开发人员不明白为什么两个带有不同标签的设备放在一个哈希集中会变成一个设备。
有没有更好的方法来做我想做的事情?
我至少有两种方式可以思考:
我更喜欢第二种方法,因为它看起来像你的Tag
模型是粘贴在设备定位器上的真实世界“标签”,除了用于显示目的之外,它忽略了它的标签。
你需要在Tag
方面实现平等吗? 这听起来不像你,所以我认为你的方法没有任何问题。
如果用户不需要知道Address
,那么您可能还会争辩说他们不需要知道基于地址的基本相等性……是吗? 如果他们不这样做,那么我会说你的方法没有错。
如果他们确实需要了解相等性,那么您可能需要重新考虑您的设计并以某种方式公开Address
。
我最终为IDevice
创建了一个新接口来实现。 新界面还允许我根据设备轻松创建相等比较器。
上述就是C#学习教程:在可变类型中实现IEquatable分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
public interface IPhysicallyEquatable { bool PhysicallyEquals(T other); int GetPhysicalHashCode(); } public class PhysicalEqualityComparer : IEqualityComparer where T : IPhysicallyEquatable { public bool Equals(T x, T y) { if (null == x) throw new ArgumentNullException("x"); if (null == y) throw new ArgumentNullException("y"); return x.PhysicallyEquals(y); } public int GetHashCode(T obj) { if (null == obj) throw new ArgumentNullException("obj"); return obj.GetPhysicalHashCode(); } } public interface IDevice : IPhysicallyEquatable { // ... }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/983107.html