很简单,当 Microsoft 首次构建 .NET 框架时,他们无法预料到依赖注入和单元测试的广泛使用。
但这是一个常见问题,不仅适用于本机 .NET 类型,也适用于 3rd 方库中的类型。处理没有抽象的类型的常用技术是使用adapter pattern 进行抽象。那么你只需要使用你的内置类型而不是库类型。
示例:UrlHelper
在 MVC 4 和之前的 UrlHelper 类没有虚拟成员,所以它不能被模拟或注入。要解决此问题,只需创建一个具有相同成员的接口(这可以使用 Visual Studio 中的“提取接口”功能轻松完成)...
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 的模拟)。
这种技术适用于大多数没有抽象的非静态类型。
正如您已经发现的那样,那里有整个库通过构建自己的适配器为您完成工作,如果可以节省一些步骤,使用它们并没有错。
如 cmets 中所述,IO.Stream 已经是一个抽象,因此在特定情况下不需要。