比较结构是否相等,无需装箱

问题描述 投票:0回答:2

我遇到了一种适用于结构

(SomeStruct)
的扩展方法,并返回该值是否等于
default(SomeStruct)
(当调用无参数构造函数时)。

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

这让我想知道该结构是否被装箱。这纯粹是出于好奇,因为根据上下文,拳击/按值传递有优点/缺点。

假设:

  1. 以下方法中的第一个是非法的,因为结构不会隐式覆盖相等运算符
    ==/!=
  2. 第二个“出现”,避免拳击。
  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)));
}

这个问题是关于确认上述假设以及我是否误解和/或遗漏了什么。

c# .net equality value-type boxing
2个回答
8
投票
  1. 以下方法中的第一个是非法的,因为结构不会隐式覆盖相等运算符 ==/!=。

确实如此。

  1. 第二个“出现”,避免拳击。

被调用方法的签名是

EqualityComparer<T>.Equals(T,T)
,它使用类型
T
作为参数,因此不需要装箱来调用。

默认比较器的实现会检查

T
是否为
IEquatable<T>
,如果是,则使用使用
IEquatable<T>.Equals
的比较器,否则使用
Object.Equals
的比较器,因此,如果结构不是
,则内部可能会应用装箱IEquatable
(“仅在需要时”)。

  1. 第三种方法应该始终对结构进行装箱,因为它正在调用 object.Equals(object o)。

确实如此。

  1. 第四个有两个可用的重载(object/T),所以我假设它也可以避免装箱。但是,目标结构需要实现 IEquatable 接口,这使得辅助扩展方法不是很有帮助。

是的,根据这个答案,它不需要拳击。这是您从

T : IEquatable
获取针对
EqualityComparer<T>.Default
特定情况的有效代码。


2
投票

让我补充一下,对于

struct
,如果不定义比较,细节就会变得复杂。

例如如何定义类型的值相等说:

您定义的任何结构都已经具有值相等的默认实现,该实现继承自Object.Equals(Object) 方法的 System.ValueType 重写。此实现使用反射来检查类型中的所有字段和属性。尽管此实现会产生正确的结果,但与您专门为该类型编写的自定义实现相比,它相对较慢。

另请参阅

C# 中默认结构相等的性能影响了解更多详细信息,包括:

Equals 和 GetHashCode 有一个优化的默认版本,但你永远不应该依赖它,因为你可能会因为无害的代码更改而停止使用它。

© www.soinside.com 2019 - 2024. All rights reserved.