【问题标题】:Comparing two structs using ==使用 == 比较两个结构
【发布时间】:2013-02-18 09:24:00
【问题描述】:

我正在尝试在 C# 中使用等于 (==) 比较两个结构。我的结构如下:

public struct CisSettings : IEquatable<CisSettings>
{
    public int Gain { get; private set; }
    public int Offset { get; private set; }
    public int Bright { get; private set; }
    public int Contrast { get; private set; }

    public CisSettings(int gain, int offset, int bright, int contrast) : this()
    {
        Gain = gain;
        Offset = offset;
        Bright = bright;
        Contrast = contrast;
    }

    public bool Equals(CisSettings other)
    {
        return Equals(other, this);
    }

    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }

        var objectToCompareWith = (CisSettings) obj;

        return objectToCompareWith.Bright == Bright && objectToCompareWith.Contrast == Contrast &&
               objectToCompareWith.Gain == Gain && objectToCompareWith.Offset == Offset;

    }

    public override int GetHashCode()
    {
        var calculation = Gain + Offset + Bright + Contrast;
        return calculation.GetHashCode();
    }
}

我正在尝试将 struct 作为我的类中的一个属性,并想检查该 struct 是否等于我尝试分配给它的值,然后再继续这样做,所以我不是指示属性已更改,但未更改,如下所示:

public CisSettings TopCisSettings
{
    get { return _topCisSettings; }
    set
    {
        if (_topCisSettings == value)
        {
            return;
        }
        _topCisSettings = value;
        OnPropertyChanged("TopCisSettings");
    }
}

但是,在我检查相等的那一行,我得到了这个错误:

运算符“==”不能应用于“CisSettings”类型的操作数和 'CisSettings'

我不知道为什么会这样,有人能指出正确的方向吗?

【问题讨论】:

  • @JMK,也许是因为你没有覆盖它...... :)
  • if (obj == null || GetType() != obj.GetType()) 是一种很奇怪的写法if(!(obj is CisSettings))
  • 另外,逻辑放错了地方:将特定类型的逻辑放在Equals(CisSettings) 并让Equals(object) 调用它,而不是反过来。
  • 另外,在 32 位整数上调用 GetHashCode 是不必要的;一个 32 位整数是它自己的哈希码。
  • 另外,如果四个数字的值相似,您的哈希码分布就会很差。

标签: c# struct equality


【解决方案1】:

您需要重载 ==!= 运算符。将此添加到您的struct

public static bool operator ==(CisSettings c1, CisSettings c2) 
{
    return c1.Equals(c2);
}

public static bool operator !=(CisSettings c1, CisSettings c2) 
{
   return !c1.Equals(c2);
}

【讨论】:

  • 别忘了重载 "!=" 运算符 ;)
  • “可能”与此无关;在不覆盖 !=. 的情况下覆盖 == 是非法
  • 如果您关心性能,您应该考虑自己实现== 运算符。上述实现导致boxing,如Microsoft 所述,“计算成本很高”。特别是因为你可以比较你的结构所包含的 4 个整数。
【解决方案2】:

当您覆盖.Equals() 方法时,== 运算符不会自动重载。你需要明确地这样做。

另请参阅Guidelines for Overriding Equals() and Operator ==CA1815: Override equals and operator equals on value types

【讨论】:

  • 只是出于好奇,是否存在您希望Equals()== 返回不同值的情况?我试图理解为什么它们有不同的实现,因为它们看起来像是完美的同义词。
  • @Nerrolken .Equals() 通常用于值相等,而 == 保留作为参考相等
【解决方案3】:

你没有implement explicitlyequality operator,所以== 不是专门为该类型定义的。

【讨论】:

    【解决方案4】:

    你应该像这样重载你的操作符:

    public static bool operator ==(CisSettings a, CisSettings b)
    {
        return a.Equals(b);
    }
    

    【讨论】:

      【解决方案5】:

      您需要明确覆盖 operator ==。

      public static bool operator ==(CisSettings x, CisSettings y) 
      {
         return x.Equals(y);
      }
      

      顺便说一句,你最好把比较代码放在public bool Equals(CisSettings other),让bool Equals(object obj)调用bool Equals(CisSettings other),这样可以避免不必要的类型检查,从而获得一些性能。

      【讨论】:

        【解决方案6】:

        您必须重载“==”运算符,但也必须重载“!=”运算符。 (Look at this Note)

        对于重载运算符,see this page

        【讨论】:

          【解决方案7】:

          创建一个方法并将两个stuct obj作为参数一一进行比较

          public Save ReturnGreater(Save online,Save local)
          {
              Save DataToSave = new Save();
              DataToSave.Score = local.Score < online.Score ? online.Score : local.Score;
              DataToSave.UnlockGuns = local.UnlockGuns < online.UnlockGuns ? online.UnlockGuns : local.UnlockGuns;
              DataToSave.UnlockLevels = local.UnlockLevels < online.UnlockLevels ? online.UnlockLevels : local.UnlockLevels;
              DataToSave.TotalLevels = local.TotalLevels;
              DataToSave.RemoveAds = local.RemoveAds;
              return DataToSave;
          }
          

          【讨论】:

            【解决方案8】:

            您还可以使用 C# v9 以来的 Record 类型和 [record struct] 值类型 从 C# v10 开始避免编写大量重复代码 没有任何意义

            有关更多详细信息,请参阅此处的 Microsoft 文档:

            Equality operators (C# reference)

            在 C# 9.0 及更高版本中可用,记录类型支持 == 和 != 默认情况下提供值相等语义的运算符。那是, 当两个记录操作数都为空或 所有字段的对应值和自动实现的属性是 相等。

            public class RecordTypesEquality
            {
                public record Point(int X, int Y, string Name);
                public record TaggedNumber(int Number, List<string> Tags);
            
                public static void Main()
                {
                    var p1 = new Point(2, 3, "A");
                    var p2 = new Point(1, 3, "B");
                    var p3 = new Point(2, 3, "A");
            
                    Console.WriteLine(p1 == p2);  // output: False
                    Console.WriteLine(p1 == p3);  // output: True
            
                    var n1 = new TaggedNumber(2, new List<string>() { "A" });
                    var n2 = new TaggedNumber(2, new List<string>() { "A" });
                    Console.WriteLine(n1 == n2);  // output: False
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-26
              • 2016-11-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多