【问题标题】:What's the most performant way to compare two values for equality?比较两个相等值的最有效方法是什么?
【发布时间】:2011-07-04 10:59:26
【问题描述】:

假设我在 C# 中有一个泛型方法,它接受两个 T 类型的值:

public void M<T>(T a, T b)
{
    ...
}

在 M() 的内部我希望比较两个输入值是否相等。由于除了它们是同一类型之外,我对它们的运行时类型一无所知,因此我可以使用 object.Equals() 静态方法来做到这一点,并让它选择最佳方式:

public void M<T>(T a, T b)
{
    if (object.Equals(a, b))
    {
        ...
    }
    else
    {
        ...
    }
}

我在这里看到的问题是当 T 不是引用类型时,两个值的不必要装箱。我想避免这种惩罚,因为 M() 被非常频繁地调用。

我的问题是:有没有更好的方法来解决这个问题?我显然对不需要过多分析 T 的解决方案感兴趣,这将抵消拳击规避带来的收益。

TIA。

【问题讨论】:

标签: c# .net generics boxing


【解决方案1】:
if(EqualityComparer<T>.Default.Equals(a,b))
{...}

这会在可用时使用IEquatable&lt;T&gt; 来避免装箱,并针对Nullable&lt;T&gt; 处理值类型、引用类型和“提升”使用以在几乎所有情况下避免装箱。

IEquatable&lt;T&gt;可用时,它必须遵循object.Equals,因此可能会发生值类型的装箱。

【讨论】:

  • 完美!我知道这门课,但由于我很少在自己的代码中使用它,所以并不能真正把这些点联系起来。谢谢,马克!
  • 我想我刚刚找到boxing still happens with IEquatable&lt;&gt; valuetypes on mono (trunk);我在那儿加了a comment to JbEvain's latest commit 征求他的意见(我在这里只花了几分钟看monodis的输出)
  • 我希望运行 EqualityComparer.Default 一次通常比使用 instance.Compare 需要更长的时间,即使在后者需要装箱的情况下也是如此。使用 EqualityComparer.Default 的优势在于,如果可以使用一次,然后在数百或数千个值类型实例上使用返回的方法。注意只有值类型和 sealed 类类型应该实现 IEquatable;如果我有我的 druthers,EqualityComparer.Default 将检查 IDontUseEquatable 的实现,并且对于任何实现它的类,使用 Object.Equals。
  • @supercat 每个T 的策略被缓存在一个字段中,所以一旦它被使用一次.Default 的所有后续使用都非常快。它不需要做任何思考 - 只是一个尊重......但是是的,将返回值捕获到一个变量中会更好。
  • @Marc Gravell:感谢您提供的信息。顺便说一句,您是否同意可继承类型不应该实现 IEquatable
猜你喜欢
  • 1970-01-01
  • 2011-05-08
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-28
  • 2018-05-21
相关资源
最近更新 更多