我在单元测试中尝试NBuilder。一个很棒的图书馆但是,我无法解释类和接口的以下结构。
在FizzWare.NBuilder
命名空间中:
ISingleObjectBuilder
SingleObjectBuilderExtensions
在FizzWare.NBuilder.Implementation
ObjectBuilder
SingleObjectBuilderExtensions
只是IObjectBuilder
上的包装。
客户端代码通常应使用名为Builder
的类,该类具有为您提供ISingleObjectBuilder
的静态方法。您永远不需要在客户端代码中实例化任何类。
现在,我不明白SingleObjectBuilderExtensions
的观点。它是否具有任何设计效益?当两个接口在同一名称空间中时,为什么不直接在ISingleObjectBuilder
中使用这些方法。
答案 0 :(得分:8)
ISingleObjectBuilder
是一个界面;接口无法提供实现。这意味着ISingleObjectBuilder
的每个实现都需要提供实现。
但是,在许多情况下,方法具有预定义的行为,只需要访问接口的其他成员(即只是ISingleObjectBuilder
的成员),因此提供每个实现都没有任何好处此
此外,向现有界面添加更多成员并不是一个好主意,因为这对所有现有实施都是一个重大变化。
扩展方法解决了这两个问题:
ISingleObjectBuilder
将它放在同一个命名空间中只是简单方便。可能的赌注是,使用ISingleObjectBuilder
的任何代码已经有using
指令导入该命名空间;因此,大多数代码只需在IDE中按.
已经在IDE中查看扩展方法。
要添加具体示例,LINQ-to-Objects可以在IEnumerable<T>
上运行。有IEnumerable<T>
个实施批次。如果他们每个人都必须编写自己的First(...)
,FirstOrDefault(...)
,Any(...)
,Select(...)
等方法,那将是巨大的负担 - 僵尸程序没有任何好处,因为在大多数情况下实现几乎完全相同。此外,回顾性地将其安装到界面上将是灾难性的。
作为旁注:方法的每类型版本始终优先于扩展方法,因此如果(在LINQ-to-Objects)你有一个实现IEnumerable<T>
的类型(对于某些T
),那个类型有一个.First()
实例方法,然后:
YourType foo = ...
var first = foo.First();
将使用您的版本,而不是扩展方法。
答案 1 :(得分:2)
扩展方法只是语法糖。它们是普通的静态方法,可以处理它们“扩展”暴露的类的公共数据。
这些扩展方法似乎不需要使用私有字段,它还使您能够使用接口而不是抽象类。每个人都知道接口是比抽象类更好的选择。
两者在同一命名空间中的原因是为了避免声明新的命名空间只是为了使用扩展方法。你发生了多少次,你试图只使用LINQ来注意intellisense中没有方法或者代码没有编译。原因是没有包含System.Linq命名空间。