问题描述
给定任何结构,使其成员都是值类型,
Given any struct, such that its members are all value types,
struct happy
{
int foo;
char bar;
}
ValueType.Equals(对象其他)
自动正常工作。
那么为什么,如果我实现 ==
运算符,我警告覆盖 ValueType.Equals
? (更正:我总是打开警告错误)
如果结构包含引用类型,这是一个安全措施吗?
覆盖ValueType.Equals
只是为了调用 base.Equals
?
什么是最佳做法?
- 覆盖等于和GetHashCode,只需调用base
- 禁用警告 #pragma
- 实际对所有成员实施相等检查或使用哈希码生成
- ?
- override Equals and GetHashCode and just call base
- disable warning with #pragma
- actually implement equality checks on all members or using hashcode generation
- ?
ValueType.Equals(object other)
works correctly automatically.
So why, if I implement the ==
operator, am I warned to override ValueType.Equals
? (Correction: I always have Warnings as Errors turned on)
Is this a safeguard in case the struct contains reference types?
Is it bad form to override ValueType.Equals just to call
base.Equals
?
What is considered best practice?
推荐答案
/// <include file='doc\Color.uex' path='docs/doc[@for="Color.operator=="]/*' />
/// <devdoc>
/// <para>
/// Tests whether two specified <see cref='System.Drawing.Color'/> objects
/// are equivalent.
/// </para>
/// </devdoc>
public static bool operator ==(Color left, Color right) {
if (left.value == right.value
&& left.state == right.state
&& left.knownColor == right.knownColor) {
if (left.name == right.name) {
return true;
}
if (left.name == (object) null || right.name == (object) null) {
return false;
}
return left.name.Equals(right.name);
}
return false;
}
/// <include file='doc\Color.uex' path='docs/doc[@for="Color.operator!="]/*' />
/// <devdoc>
/// <para>
/// Tests whether two specified <see cref='System.Drawing.Color'/> objects
/// are equivalent.
/// </para>
/// </devdoc>
public static bool operator !=(Color left, Color right) {
return !(left == right);
}
/// <include file='doc\Color.uex' path='docs/doc[@for="Color.Equals"]/*' />
/// <devdoc>
/// Tests whether the specified object is a
/// <see cref='System.Drawing.Color'/>
/// and is equivalent to this <see cref='System.Drawing.Color'/>.
/// </devdoc>
public override bool Equals(object obj) {
if (obj is Color) {
Color right = (Color)obj;
if (value == right.value
&& state == right.state
&& knownColor == right.knownColor) {
if (name == right.name) {
return true;
}
if (name == (object) null || right.name == (object) null) {
return false;
}
return name.Equals(name);
}
}
return false;
}
/// <include file='doc\Color.uex' path='docs/doc[@for="Color.GetHashCode"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public override int GetHashCode() {
return value.GetHashCode() ^
state.GetHashCode() ^
knownColor.GetHashCode();
}
}
Mono的平等实施:
Mono's equality implementation:
/// <summary>
/// Equality Operator
/// </summary>
///
/// <remarks>
/// Compares two Color objects. The return value is
/// based on the equivalence of the A,R,G,B properties
/// of the two Colors.
/// </remarks>
public static bool operator == (Color left, Color right)
{
if (left.Value != right.Value)
return false;
if (left.IsNamedColor != right.IsNamedColor)
return false;
if (left.IsSystemColor != right.IsSystemColor)
return false;
if (left.IsEmpty != right.IsEmpty)
return false;
if (left.IsNamedColor) {
// then both are named (see previous check) and so we need to compare them
// but otherwise we don't as it kills performance (Name calls String.Format)
if (left.Name != right.Name)
return false;
}
return true;
}
/// <summary>
/// Inequality Operator
/// </summary>
///
/// <remarks>
/// Compares two Color objects. The return value is
/// based on the equivalence of the A,R,G,B properties
/// of the two colors.
/// </remarks>
public static bool operator != (Color left, Color right)
{
return ! (left == right);
}
/// <summary>
/// Equals Method
/// </summary>
///
/// <remarks>
/// Checks equivalence of this Color and another object.
/// </remarks>
public override bool Equals (object obj)
{
if (!(obj is Color))
return false;
Color c = (Color) obj;
return this == c;
}
/// <summary>
/// Reference Equals Method
/// Is commented out because this is handled by the base class.
/// TODO: Is it correct to let the base class handel reference equals
/// </summary>
///
/// <remarks>
/// Checks equivalence of this Color and another object.
/// </remarks>
//public bool ReferenceEquals (object o)
//{
// if (!(o is Color))return false;
// return (this == (Color) o);
//}
/// <summary>
/// GetHashCode Method
/// </summary>
///
/// <remarks>
/// Calculates a hashing value.
/// </remarks>
public override int GetHashCode ()
{
int hc = (int)(Value ^ (Value >> 32) ^ state ^ (knownColor >> 16));
if (IsNamedColor)
hc ^= Name.GetHashCode ();
return hc;
}
struct happy : IEquatable<happy>
{
int foo;
char bar;
public bool Equals(happy value)
{
return ((this.foo == value.foo) && (this.bar == value.bar));
}
override bool Equals(object obj)
{
return ((obj is happy) && obj.Equals(this));
}
public static bool operator ==(happy left, happy right)
{
return left.Equals(right);
}
public static bool operator !=(happy left, happy right)
{
return !left.Equals(right);
}
public override int GetHashCode()
{
return foo.GetHashCode() ^ (bar.GetHashCode() << 5);
}
}
(GetHashCode实现只是一个简单的例子,你必须要注意有你选择的算法没有碰撞)
希望这会有所帮助。
(GetHashCode implementation is just a quick example, you have to take care that there are no collisions in the algorithm you choose)
Hope this helps.
这篇关于在结构上实现==的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!