比较不装箱的结构是否相等

Comparing structs for equality without boxing

我遇到了一个适用于结构 (SomeStruct) 和 returns 的扩展方法,无论值是否等于 default(SomeStruct)(当调用无参数构造函数时)。

public static bool IsDefault<T> (this T value)
    where T : struct
{
    return (!EqualityComparer<T>.Default.Equals(value, default(T)));
}

这让我想知道结构是否被装箱了。这纯粹是出于好奇,因为根据上下文,值有 pros/cons 到 boxing/passing。

假设:

  1. 以下第一个方法是非法的,因为结构不会隐式覆盖相等运算符 ==/!=
  2. 第二个"appears"避免装箱
  3. 第三种方法应始终将结构框起来,因为它正在调用 object.Equals(object o)
  4. 第四个有两个重载可用 (object/T) 所以我假设它也会避免装箱。但是,目标结构需要实现 IEquatable<T> 接口,使得辅助扩展方法不是很有用。

变化:

public static bool IsDefault<T> (this T value)
    where T : struct
{
    // Illegal since there is no way to know whether T implements the ==/!= operators.
    return (value == default(T));
}

public static bool IsDefault<T> (this T value)
    where T : struct
{
    return (!EqualityComparer<T>.Default.Equals(value, default(T)));
}

public static bool IsDefault<T> (this T value)
    where T : struct
{
    return (value.Equals(default(T)));
}

public static bool IsDefault<T> (this T value)
    where T : struct, IEquatable<T>
{
    return (value.Equals(default(T)));
}

这个问题是关于确认上述假设,如果我误解了and/or遗漏了一些东西。

  1. The first of the following methods is illegal since structs do not implicitly override the equality operators ==/!=.

正确。

  1. The second "appears" to avoid boxing.

被调用方法的签名是EqualityComparer<T>.Equals(T,T),参数使用T类型,所以不需要装箱调用。

默认比较器的实现检查 T 是否为 IEquatable<T>,如果是,则使用使用 IEquatable<T>.Equals 的比较器,否则使用 Object.Equals 的比较器,因此如果结构不是 IEquatable ('only if needed').

,内部可能会应用装箱
  1. The third method should always box the struct since it's calling object.Equals(object o).

正确。

  1. The fourth has both overloads available (object/T) so I'm assuming it will avoid boxing as well. However, the target struct would need to implement the IEquatable interface, making the helper extension method not very helpful.

是的,根据 this SO answer,它不需要装箱。这是您从 EqualityComparer<T>.Default.

中针对 T : IEquatable 的特定情况获得的有效代码

让我补充一下 structs,如果你不定义比较,细节会变得复杂。

例如 How to define value equality for a type 表示:

Any struct that you define already has a default implementation of value equality that it inherits from the System.ValueType override of the Object.Equals(Object) method. This implementation uses reflection to examine all the fields and properties in the type. Although this implementation produces correct results, it is relatively slow compared to a custom implementation that you write specifically for the type.

另请参阅 Performance implications of default struct equality in C# 了解更多详细信息,包括:

There is an optimized default version for Equals and GetHashCode but you should never rely on it because you may stop hitting it with an innocent code change.