在结构上实现== [英] Implementing == on a struct

查看:50
本文介绍了在结构上实现==的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定任何结构,使其成员都是值类型,

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
  • 实际对所有成员实施相等检查或使用哈希码生成

  • ValueType.Equals(object other) works correctly automatically.

    So why, if I implement the == operator, am I required 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?

    • override Equals and GetHashCode and just call base
    • disable warning with #pragma
    • actually implement equality checks on all members or using hashcode generation
    • ?
    • 推荐答案

      请参阅我对该问题的另一条评论的评论。



      您只需要以一致的方式实现上述方法;并且您的代码对此负全部责任。

      您的结构中的组合引用类型实例成员没有安全措施。这也是您的唯一责任。这个想法是:你描述逻辑,语义等价。您可以完全忽略这些成员中的差异,您可以要求这些引用成员的引用等效,或者您可以允许它们在某些其他语义含义或上述任意组合中等效引用。您只需要假设使用您的结构的代码应该能够自由地使用这三个相等/不相等的方法/运算符中的任何一个,并且您希望任何此类检查的结果是一致的。



      -SA
      Please see my comment to another comment to the question.

      You just need to implement the mentioned methods in a consistent way; and your code takes sole responsibility for that.
      There are no a "safeguard" for the composed reference-type instance members in your structure. This is also your sole responsibility. The idea is: you describe logical, semantic equivalence. You can completely ignore differences in those members, you can require referential equivalence of those reference members, or you can allow them to be referentially different by equivalent in some other semantic meaning, or any combination of the above. You just need to assume that the code using your structure should be able to freely use any of these three equality/non-equality methods/operators, and you want the results of any of such checks to be consistent.

      —SA


      我比较了 Microsoft 的来源Mono 实现 System.Drawing.Color



      重写等于并检查每个成员是否相等。

      Microsoft在 Equals == 中都这样做。

      Mono在 == 中执行此操作,并调用 == 以测试中的相等性等于



      GetHashCode 被覆盖。 Microsoft XORed成员的哈希码,即 value.GetHashCode()^ state.GetHashCode()等; Mono做同样的事情,但是将每个哈希码的位移位到最后16位。



      两者都定义!= as !(a == b)



      两者都没有实现 IEquatable< color>< ; / color>



      对于任何有兴趣的人,



      微软的平等实施:

      I compared the sources of both Microsoft's and Mono's implementation of System.Drawing.Color.

      Equals is overridden and each member is checked for equality.
      Microsoft does this both in Equals and in ==.
      Mono does this in ==, and calls == to test equality in Equals.

      GetHashCode is overriden. Microsoft XORed the member's hashcodes i.e. value.GetHashCode() ^ state.GetHashCode() etc.; Mono does the same but bit shifts each hashcode by 16 bits to the last.

      Both define != as !(a == b).

      Neither implements IEquatable<color></color>.

      For anyone interested,

      Microsoft's equality implementation:
          /// <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;
      		}


      最佳做法是:

      - 实施 IEquatable< happy> 界面

      - 覆盖 GetHashCode()方法

      - 设置 = = != 运算符使用 Equals()方法。



      这样:



      Best practice is:
      - implement IEquatable<happy> interface
      - override GetHashCode() method
      - set your == and != operators to use the Equals() method.

      This way:

      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.


      这篇关于在结构上实现==的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆