为什么.Net框架中的每个类都没有相应的接口?

Tho*_*enz 13 .net bdd interface mocking

自从我开始以测试/行为驱动的方式开发以来,我欣赏能够模拟每个依赖项.

由于像Moq这样的模拟框架在被告知模拟界面时效果最好,我现在几乎为每个创建b/c的类实现一个接口,最有可能我最终必须在测试中模拟它.好吧,无论如何,编程到接口是很好的做法.

有时,我的类依赖于.Net类(例如FileSystemWatcher,DispatcherTimer).在这种情况下,拥有一个接口会很棒,所以我可以依赖于IDispatcherTimer,以便能够传递一个模拟并模拟其行为,以查看我的被测系统是否正确反应.

不幸的是,上面提到的两个类都没有实现这样的接口,所以我不得不求助于创建适配器,除了继承原始类并且符合接口之外什么也不做,然后我可以使用它.

以下是DispatcherTimer和相应接口的适配器:

 using System;
using System.Windows.Threading;

public interface IDispatcherTimer
{
    #region Events

    event EventHandler Tick;

    #endregion

    #region Properties

    Dispatcher Dispatcher { get; }

    TimeSpan Interval { get; set; }

    bool IsEnabled { get; set; }

    object Tag { get; set; }

    #endregion

    #region Public Methods

    void Start();

    void Stop();

    #endregion
}

/// <summary>
/// Adapts the DispatcherTimer class to implement the <see cref="IDispatcherTimer"/> interface.
/// </summary> 
public class DispatcherTimerAdapter : DispatcherTimer, IDispatcherTimer
{
}
Run Code Online (Sandbox Code Playgroud)

虽然这不是世界末日,但我想知道,为什么.Net开发人员没有花时间让他们的类从get开始实现这些接口.这让我很困惑,因为现在微软内部的良好实践有很大的推动力.

有没有人有任何(可能是内部)信息为什么这个矛盾存在?

LBu*_*kin 11

接口可能非常有用,而且在.NET类库中有一些遗漏,其中接口(或两个)可能使事情变得更清晰或更简单,这当然是不幸的.

但是,您必须从另一个角度考虑它.接口是合同.接口代表协议,其中合同的消费者和实施者定义他们想要如何交互.这当然也适用于类,但接口被视为更正式且不可变的合同形式.您不希望接口不断变化.接口很有用,因为它们的稳定性.

话虽如此,创建一个简单地复制类的公共接口的接口并不一定能创造价值.特别是如果不可能有多个接口的实现者,或者接口的解耦不会产生明确的价值.实际上,您可能会认为过早创建接口可能是有害的,因为它会锁定可能很难理解的接口或者不能完全捕获抽象的接口.仅仅因为模拟,作为一种实践,适用于接口并不是为每个类创建接口的充分理由.

在您引用的示例中,不清楚界面是否会创建超出您更容易模拟的有意义的价值.请记住,添加到.NET BCL的每种其他类型都会使学习曲线更加陡峭 - 更多类型意味着需要学习和理解更多内容.

最后,为了直接解决您的问题,Microsoft必须决定在每个版本上投入.NET投入多少时间和精力.必须设计,实现,记录,测试,维护每个功能和每种类型.由于功能不是免费的,因此必须有一个令人信服的理由来实现它们以克服巨大的成本障碍.延迟.NET的发布以添加可能永远不会广泛使用(甚至可能有害)的接口并不是大多数开发人员所希望的.


Mar*_*ann 6

这是一个古老的讨论中TDDers认为太少接缝在BCL,而微软往往是非常保守,他们所提供的接缝.许多BCL实现严重依赖内部密封类,这真的会损害可测试性.

我真诚地相信,.NET的第一个版本永远不会出现可测试性,但后来,微软已经意识到这个问题.但是,意识到这个问题并不等于做足够的事情.

虽然它变得更好,但微软反对提供更开放的BCL的最大理由是它给开发工作带来了几个负担:

  • 他们必须确保接口的每个消费者都不会破坏Liskov替换原则.他们的论点是,这样做还需要额外的测试工作.
  • 他们希望通过发布一个没有经过深思熟虑的API来确保他们不会将自己描绘成一个角落.这里的论点是,一旦BCL中有类型,由于向后兼容性原因,很难删除.

我不是说我完全同意这些论点,但那些是微软最常提供的论点.