提问人:Alex 提问时间:1/24/2023 更新时间:1/24/2023 访问量:208
结构体类型比较
Struct type comparison
问:
假设我有一个 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 个问题:
- 是否有选项可以区分具有相同值的两个不同结构变量?
- 还有其他方法可以解决我的问题吗?
谢谢
答:
是否有选项可以区分具有相同值的两个不同结构变量?
不,结构是所谓的值类型。它们仅由其值定义,没有参考。如果要区分两个值相等的实例,则必须使用类而不是结构。类是引用类型,因此即使它们具有相等的值也是可区分的,因为它们具有不同的引用。
但是,在这种情况下,您还有它们在集合中的位置,可以用来区分它们(从根本上来说,这也是某种参考)。
还有其他方法可以解决我的问题吗?
如上所述,您可以使用该职位。下面是一个没有 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() 进行相等比较,因为相等的哈希代码并不能保证被比较的对象实际上相等。
评论
var
int
bool
结构将通过从其字段生成的哈希码自动地相互比较,因此您应该能够使用该方法来确定集合中是否存在任何重复项。执行此操作的一种简单方法是按结构本身对集合进行分组,然后比较分组项和原始集合的计数。如果有任何相同的项目,它们将被分组在一起,并且分组的项目计数将小于原始集合计数: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
评论
I found out that hashes are actually equal for structures having same values
- 这并不奇怪,因为这是他们存在的目的。struct
if (x == 5)
if (x.Equals(5))
where T: struct, IEqualityOperators<T,T,bool>