【问题标题】:Extension methods overload choice扩展方法重载选择
【发布时间】:2012-04-09 05:49:00
【问题描述】:

我有两种扩展方法:

public static IPropertyAssertions<T> ShouldHave<T>(this T subject)
{
    return new PropertyAssertions<T>(subject);
}

public static IPropertyAssertions<T> ShouldHave<T>(this IEnumerable<T> subject)
{
    return new CollectionPropertyAssertions<T>(subject);
}

现在我写了一些使用它的代码:

List<Customer> collection2 = new List<Customer>(); 
collection2.ShouldHave(); //first overload is chosen
IEnumerable<Customer> collection3 = new List<Customer>(); 
collection3.ShouldHave(); //second overload is chosen

仅当我明确指定 IEnumerable 类型时才选择第二次重载。有没有办法在这两种情况下都选择第二个重载?

【问题讨论】:

  • collection1collection2 之间没有区别。它们是完全相同的代码,只是编写方式不同。
  • @svick,是的,但我想显示所有语法选项
  • 请注意,它是一种扩展方法这一事实是无关紧要的;重载决议像普通的静态方法一样处理它。
  • 好的,删除第一个。最好避免可以在 any 对象上工作而不受任何约束的扩展方法,因为噪音太大。同样值得注意的是源代码变得多么不可读。应该有什么?根本不要使用扩展方法,将其设为常规的公共静态方法。
  • @HansPassant,它实际上是流利的语法,我只是没有显示像 collection.ShouldHave().AllProperties().EqualTo(...) 这样的其余调用

标签: c# .net extension-methods overloading fluent-assertions


【解决方案1】:

第一个重载是一个更好的匹配,因为 T 被推断为List&lt;Customer&gt;,它给出了一个精确匹配。对于第二个重载,它会将 T 推断为 Customer,因此参数将是 IEnumerable&lt;Customer&gt;,与 List&lt;Customer&gt; 相比不太精确。

【讨论】:

    【解决方案2】:

    不这么认为。不要认为在 这种 的情况下总是会调用 IEnumerable&lt;T&gt; 重载,因为它在 T 类型方面具有less 精确匹配。如果您不指定具体的IEnumerable&lt;T&gt;,则最佳匹配将始终是第一个方法,在 this 情况下。

    【讨论】:

      【解决方案3】:

      在 Fluent Assertion 2.0 中,我终于设法以体面的方式解决了上述问题。在此处阅读所有相关信息: http://www.dennisdoomen.net/2012/09/asserting-object-graph-equivalence.html

      【讨论】:

        【解决方案4】:

        ShouldHave() 有双重含义。在第一种情况下,ShouldHave() 有一个关于主题参数提供的对象的返回。在第二种情况下,返回的是枚举中的项目,而不是枚举本身。

        如果我创建自己的集合并且我想测试这个集合本身(而不是项目),我当然希望调用 ShouldHave(this T subject) 而不是 ShouldHave(this IEnumerable subject)。

        也许您应该重新考虑您的设计。 第二个 ShouldHave() 做了两件事,因此应该拆分为一个提取集合项的方法和一个对您已经拥有的第一个 ShouldHave() 的调用。

        【讨论】:

        • 这正是我们想要做的,但我们在 C# 编译器的重载解析方面遇到了一些问题。
        • C# 编译器是正确的,因为它更喜欢完美匹配而不是首先需要类型转换的匹配。我认为你的设计是不完美的,你希望它通过 C# 编译器不完美来解决。如果我确实想将 ShouldHave(this T subject) 应用于我的收藏怎么办?为什么要阻止这种情况?
        • 但要保持认真,你有道理。但是扩展方法的全部目的是在不触及原始代码的情况下扩展现有类型。所以我的典型做法是想出一个漂亮流畅的语法,然后尝试实现它。不幸的是,这种特殊情况不容易解决。
        • 我希望 x.ShouldHave() 与 x 一起工作,而不是与 x 的任何属性或 x 的项目一起工作,以防 x 是 IEnumerable。我更喜欢 x.Enumeration().ShouldHave() 以防它是一个枚举。您希望通过将两个操作合二为一来简化此操作。如果你真的想要,你可以在第一个方法中使用反射来查看 subject (= T) 是否实现 IEnumerable (其中 T 是另一个 T,令人困惑)并调用第二个方法。我不喜欢那样。现在 ShouldHave 有 2 个选项,其行为与正常情况不同(仅通过查看方法的界面我看不到这一点)。
        猜你喜欢
        • 2012-06-15
        • 1970-01-01
        • 1970-01-01
        • 2016-08-14
        • 1970-01-01
        • 2015-02-26
        • 2013-04-08
        • 2023-03-23
        • 1970-01-01
        相关资源
        最近更新 更多