所以我在一家公司工作,我在这里比较新,但我在一些生产代码中遇到了一些非常奇怪的东西,据说这些代码是由一个在C#中比我自己知道更多的人写的。事情是一种特殊的方式“。因此,我试图想出理由去做我要解释的事情,给出怀疑的好处,但我无法想出任何东西。
IList<Facility> Facilities = new List<Facility>();
以上几行是问题的核心......整个代码中的其他奇怪之处在于无法为某些事物使用接口,因此必须在使用之前将数据复制回List中(例如,通过webservice导出,不允许使用接口,必须是IList的实现)
现在我理解接口是很精彩的,你可以编写方法,希望接口中的方法存在于传递给你的方法的实现上但是......
有人可以帮助我吗?有人能想到你立即将List转发回应用程序数据层界面的原因吗?
另外只是为了说清楚......这些列表也不用于可互换的数据类型,这发生在定义和存储List的位置,并且存储了每个数据类型的IList。
谢谢!
答案 0 :(得分:6)
在层次结构中使用尽可能高的类是一种良好的做法。因此,如果您只需要遍历值,则只应公开IEnumerable<T>
:
IEnumerable<Facility> Facilities = new List<Facility>();
// now you can foreach over the facilities or chain with LINQ
如果您需要索引器访问权限,可以使用IList<Facility>
IList<Facility> Facilities = new List<Facility>();
// in addition to looping now you can access facilities by index
// and you can also add and remove facilities
在设计某些API时,在层次结构中暴露最高级别类/接口背后的想法是,这样您就隐藏了使用List<T>
的实现细节。如果你明天发明了HyperSpecialListWhichIsVeryFast<T>
,它实现了你与API的消费者达成一致的合同,那么这个消费者不需要在他的代码中改变任何东西。他不在乎。他与IEnumerable<T>
合作,因为他需要的只是循环。感谢您的新列表,他的代码运行得更快,而无需更改任何内容。
但是现在使用历史书中的非通用的.NET 1.0弱类型集合就像巫术魔术一样:
IList Facilities = new List<Facility>();
想不出为什么这会有用。向下转换为非泛型版本将强制客户端进行转换以访问基础类型T
。这样他就失去了泛型提供的所有编译时安全性。
答案 1 :(得分:1)
关于您打算如何使用Facilities
变量的全部内容。如果您只打算以IList
开启它(您只打算按照该接口中的定义调用它上面的方法),那么声明变量是合理的,以强制执行您不尝试的约束。调用在该接口上定义 not 的方法。这样,您可以轻松地将您使用的数据结构替换为IList
的另一个实现。
我自己,除非我有特殊需要,否则我通常会避免使用非通用版本。 (即我会使用IList<Facility>
而不是IList
)使用非泛型版本(在代码中的其他位置)的一种可能方案是它显然不要求其他代码知道任何关于Facility
- 它可以作为一般对象列表在列表上运行。
答案 2 :(得分:0)
如果一个接口包含一个人所需的所有成员,那么使用该接口的每个地方都没有太大的缺点,只有构造函数调用和静态方法(其中一个)必须使用类(*))。使用接口而不是类的最大问题也是这样做的最大原因:指定接口的代码通常与使用该类的代码笨拙地接口;如果将来可能需要使用该接口,那么从一开始就这样做可以避免以后可能很尴尬的重构工作。
(*)如果我有我的druthers,接口可以指定一个用于构造函数或静态方法的类,这样如果一个声明接口IFoo指定它与Foo“合作”,那么IFoo.Bar()
将是相当于Foo.Bar()
,new IFoo(3)
相当于new Foo(3)
'。不幸的是,没有这样的功能;如果确实如此,我怀疑接口的使用会更加一致。