结构体类型比较

Struct type comparison

提问人:Alex 提问时间:1/24/2023 更新时间:1/24/2023 访问量:208

问:

假设我有一个 IEnumerable<T>其中 T 是结构类型。对于集合的每个元素,我想检查是否有另一个具有相同值的元素。

首先,我想到了这样的事情:

IEnumerable<T> collection = someInput;

foreach(var element in collection)
{
  try
  {
    collection.First(x => x == element &&
                          x.GetHashCode() =! element.GetHashCode());

    DoA(element);
  }
  catch
  {
    DoB(element);
  }
}

但后来我发现,对于具有相同值的结构,哈希实际上是相等的。显然,也不是一种方法。Object.ReferenceEquals(x, element)

所以,有 2 个问题:

  1. 是否有选项可以区分具有相同值的两个不同结构变量?
  2. 还有其他方法可以解决我的问题吗?

谢谢

C# 变量结构 类型 比较

评论

6赞 GSerg 1/24/2023
I found out that hashes are actually equal for structures having same values- 这并不奇怪,因为这是他们存在的目的
1赞 dbc 1/24/2023
是否有选项可以区分具有相同值的两个不同结构变量?——你这是什么意思? 值存在于堆栈上,而不是堆上,因此当您分配一个值时,您可以复制它。因此,结构体不存在引用相等的概念。考虑到这一点,你想完成什么?请编辑您的问题以澄清。struct
1赞 GSerg 1/24/2023
这回答了你的问题吗?C# LINQ 在列表中查找重复项
1赞 GSerg 1/24/2023
@Adam所以你是说不可能,必须用吗?if (x == 5)if (x.Equals(5))
1赞 Alexei Levenkov 1/24/2023
@Adam OP确实适当地限制了通用方法,以允许与 进行比较,这是合理的。(无论情况是否可能还有待商榷,我希望了解这些接口的人通常不太可能遇到值类型的问题)where T: struct, IEqualityOperators<T,T,bool>

答:

3赞 UnrealSoftware 1/24/2023 #1

是否有选项可以区分具有相同值的两个不同结构变量?

不,结构是所谓的值类型。它们仅由其值定义,没有参考。如果要区分两个值相等的实例,则必须使用类而不是结构。类是引用类型,因此即使它们具有相等的值也是可区分的,因为它们具有不同的引用。

但是,在这种情况下,您还有它们在集合中的位置,可以用来区分它们(从根本上来说,这也是某种参考)。

还有其他方法可以解决我的问题吗?

如上所述,您可以使用该职位。下面是一个没有 LINQ 的简单基本实现。您当然可以使用 LINQ 制作一个更短的。

    for (var i = 0; i < collection.Count; i++)
    {
        var foundEqual = false;
        for (var j = 0; j < collection.Count; j++)
        {
            if (j != i && collection[i] == collection[j])
            {
                foundEqual = true;
                break;
            }
        }
        
        if (foundEqual)
        {
            DoA(collection[i]);
        }
        else
        {
            DoB(collection[i]);
        }   
    }

如果你的结构还没有实现 IEquatable,你必须实现它才能使相等比较工作。请在此处查看解释和示例:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type

您永远不应该依赖 GetHashCode() 进行相等比较,因为相等的哈希代码并不能保证被比较的对象实际上相等。

评论

0赞 GSerg 1/24/2023
所以你是说,如果一个整数数组恰好包含两个相等的整数,就没有办法知道它们在数组中的不同位置?
0赞 UnrealSoftware 1/24/2023
好点子。我以更普遍的方式看待这个问题。当然,在这种特定情况下,您仍然可以按位置进行区分。好点子。会编辑!
1赞 GSerg 1/24/2023
现在,您的代码意味着哈希码的相等意味着对象的相等;事实并非如此。
0赞 UnrealSoftware 1/24/2023
再次感谢。你是完全正确的。调整了答案!
0赞 Alex 1/25/2023
谢谢你的回答!我只是好奇在您的代码中使用而不是显式/类型声明。这有什么意义?它是否在某种程度上使你的代码更清晰?varintbool
0赞 Rufus L 1/24/2023 #2

结构将通过从其字段生成的哈希码自动地相互比较,因此您应该能够使用该方法来确定集合中是否存在任何重复项。执行此操作的一种简单方法是按结构本身对集合进行分组,然后比较分组项和原始集合的计数。如果有任何相同的项目,它们将被分组在一起,并且分组的项目计数将小于原始集合计数:Equals

bool hasDuplicates = collection.GroupBy(i => i).Count() < collection.Count();

通常,您可以使用以下方法比较项目:Equals

public bool HasDuplicateElement<T>(IEnumerable<T> items) where T : struct
{
    if (items == null || items.Count() < 2) return false;

    for(int i = 0; i < items.Count() - 1; i++)
    {
        for (int j = i + 1; j < items.Count(); j++)
        {
            if (items.ElementAt(i).Equals(items.ElementAt(j))) return true;
        }
    }

    return false;
}

请注意,如果结构具有引用类型字段,并且它们没有有意义的相等实现(即它们使用默认的引用相等),则必须编写自己的字段并将其传递给方法。IEqualityComparer<T>GroupBy