5

简而言之,我正在寻找关于以下两种方法中的哪一种应该优先(以及为什么)的指导:

static IEnumerable<T> DistinctA<T>(this IEnumerable<T> xs)
{
    return new HashSet<T>(xs);
}

static IEnumerable<T> DistinctB<T>(this IEnumerable<T> xs) where T : IEquatable<T>
{
    return new HashSet<T>(xs);
}
  • 赞成的论点DistinctA:显然,约束 onT不是必需的,因为HashSet<T>不需要它,并且因为 any 的实例T保证可转换为,它提供与(即两个方法和)System.Object相同的功能。(虽然非泛型方法会导致值类型的装箱,但这不是我在这里关心的。)IEquatable<T>EqualsGetHashCode

  • 支持 的论点DistinctB:通用参数约束虽然不是绝对必要的,但使调用者可以看到该方法将比较 的实例T,因此是一个信号,Equals并且GetHashCode应该正确地工作于T。(毕竟,在没有显式实现的情况下定义新类型Equals并且GetHashCode很容易发生,因此约束可能有助于及早发现一些错误。)

问题:是否有既定并记录在案的最佳实践建议何时指定此特定约束 ( T : IEquatable<T>),何时不指定?如果没有,上述论点之一是否有任何缺陷?(在这种情况下,我更喜欢经过深思熟虑的论点,而不仅仅是个人意见。)

4

2 回答 2

3

虽然我对 Pieter 回答的评论完全正确,但我已经重新考虑了您所指的 Distinct 的确切情况。

这是一个 LINQ 方法契约,而不仅仅是一个方法。

LINQ 旨在成为由各种提供者实现的通用门面。Linq2Objects 可能需要 IEquatable,Linq2Sql 也可能需要 IEquatable,但 Linq2Sql 可能不需要甚至根本不使用,并且完全忽略 IEquatableness,因为比较是由 DB SQL 引擎进行的。

因此,在 LINQ 方法定义层,指定 IEquatable 的要求是没有意义的。它将限制和约束未来的 LINQ 提供者在他们的特定域中确实不需要关心的一些事情,并注意 LINQ 实际上通常都是关于域特定性的,因为很多时候 LINQ 表达式和参数实际上从来没有作为代码运行,但它们会被分析并重新转换为 SQL 或 XPaths 等其他结构。在这种情况下省略约束是合理的,因为您无法真正知道您的未来和未知域提供者将真正需要从呼叫者,召集者。Linq-to-Mushrooms 可能需要使用 IToxinEquality 而不是 IEquatable!

但是,当您设计将明确用作可运行代码的接口/合同时(不仅仅是仅用作配置或声明的表达式树),那么我认为不提供约束没有任何意义。

于 2013-04-08T22:47:59.637 回答
2

首先考虑何时使用这两种机制中的哪一种可能很重要;我只能想到两个:

  1. 当代码被翻译成另一种语言时(无论是 C# 的后续版本,还是 Java 等相关语言,或者 Haskell 等完全不同的语言)。在这种情况下,通过为自动或手动翻译器提供更多信息,第二个定义显然更好。
  2. 当不熟悉代码的用户阅读它以了解如何调用该方法时。同样,我相信第二个显然更好,因为它可以轻松地向这样的用户提供更多信息。

我想不出在什么情况下会首选第一个定义,并且它实际上比个人偏好更重要。

别人的想法?

于 2013-04-08T22:27:21.177 回答