为什么 C# 标准库 (mscorlib) 不为其 类 提供抽象?

Why doesn't the C# Standard Library (mscorlib) provide abstractions for its classes?

C# 标准库目前没有为其大多数产品提供 abstractions/interfaces,例如 FileHttpClient 等。(实际上,我不确定这个VB.NET、F#等都是这种情况,所以我们暂时坚持使用C#。)然而,需求相当高,因为单元测试实际上需要你模拟出对IO、网络等的依赖。有有很多自制解决方案,其中大部分 "wrappers."

我很好奇的是,为什么标准库没有通过简单地在库中包含接口来简化此操作。有设计原因吗?文体?

很简单,Microsoft 在最初构建 .NET 框架时无法预料到依赖注入和单元测试的广泛使用。

但这是一个常见问题,不仅适用于本机 .NET 类型,也适用于第 3 方库中的类型。处理没有抽象的类型的常用技术是使用 adapter pattern 进行抽象。然后你只需要使用你的 built-in 类型而不是库类型。

示例:UrlHelper

在 MVC 4 和之前 UrlHelper class 没有虚拟成员,所以它不能被模拟或注入。要解决这个问题,只需要创建一个具有相同成员的接口(这可以使用 Visual Studio 中的 "extract interface" 功能轻松完成)...

public interface IUrlHelper
{
    string Action(string actionName);
    string Action(string actionName, object routeValues);
    string Action(string actionName, string controllerName);
    string Action(string actionName, string controllerName, object routeValues);
    string Action(string actionName, string controllerName, object routeValues, string protocol);
    string Action(string actionName, string controllerName, RouteValueDictionary routeValues);
    string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName);
    string Action(string actionName, RouteValueDictionary routeValues);
    string Content(string contentPath);
    string Encode(string url);
    RequestContext RequestContext { get; }
    RouteCollection RouteCollection { get; }
    string RouteUrl(object routeValues);
    string RouteUrl(string routeName);
    string RouteUrl(string routeName, object routeValues);
    string RouteUrl(string routeName, object routeValues, string protocol);
    string RouteUrl(string routeName, RouteValueDictionary routeValues);
    string RouteUrl(string routeName, RouteValueDictionary routeValues, string protocol, string hostName);
    string RouteUrl(RouteValueDictionary routeValues);
    bool IsLocalUrl(string url);
    string HttpRouteUrl(string routeName, object routeValues);
    string HttpRouteUrl(string routeName, RouteValueDictionary routeValues);
}

...然后创建一个继承UrlHelper并实现IUrlHelper...

的适配器类型
public class UrlHelperAdapter : UrlHelper, IUrlHelper
{
    private UrlHelperAdapter(RequestContext requestContext)
        : base(requestContext)
    {
    }

    public UrlHelperAdapter(RequestContext requestContext, RouteCollection routeCollection)
        : base(requestContext, routeCollection)
    {
    }
}

完成后,您可以将 IUrlHelper 传递给任何方法或构造函数,您只需将 UrlHelperAdapter 作为具体类型传递(或者如果使用模拟框架,构建一个模拟IUrlHelper).

此技术适用于大多数 non-static 没有抽象的类型。

正如您已经发现的那样,有很多库可以通过构建自己的适配器为您完成跑腿工作,如果可以为您节省一些步骤,使用它们并没有错。

As mentioned in the comments, IO.Stream already is an abstraction so there is no need in that specific case.