混淆C#duck typing,隐式转换和不一致

1 c# design-decisions

每个人似乎都喜欢鸭子打字,如果它看起来像鸭子,就像一只鸭子,像鸭子一样对待它.C#4.0允许鸭子打字和当前支持它在一些情况下(参见"C#长时间使用鸭子打字"在http://www.eioba.com/a75370/how_duck_typing_benefits_c_developers)

现在......几乎所有东西都有.AnotherType().我不能理解int需要.ToString()但是当一个列表传递给需要obj []的函数时,它确实需要一个.ToArray().这似乎不一致.

有人可以解释这些不一致,解释为什么.ToArray有意义(或任何其他设计决定)或给我任何类型的见解?

Shu*_*oUk 7

几乎任何集合都应该提供一种方法,允许从其他公共集合创建它,或者允许它被制作成(甚至更好地对待)其他常见集合.

数组很强大但很复杂,因为它们(固有地)可变,但允许在需要时进行一些强大的优化(例如,有效的快速实现实现真的需要能够交换元素).
序列(IEnumerable<T>对你而言)非常好,因为它们对自己的要求很少(包括任何修改它们的方法),这意味着期望它们的代码往往非常灵活且广泛有用.

能够简单轻松地从另一个集合中获取特定类型的集合允许您编写代码,使其适用于所需的结构,但可以通过简单的翻译调用轻松地与许多其他类型的结构进行交互.如果后来证明这是性能问题,则可能必须避免转换并使更多的代码库了解底层类型,但从一开始就可以干净利落地快速编写.

很多api已经存在,期望某种收集,可能的原因包括:

  • 写在2.0变更之前,使得集合在.Net中更加丰富
  • 因为他们知道他们需要改变状态,所以他们让调用者负责提供要改变的状态(比如排序函数)
  • 他们的写得不好

值得注意的是,除了阵列之外,.Net pre 2.0中缺少任何类型的强类型集合意味着很多BCL api,事后看来,设计很差.BCL中的反射api是值得注意的例子,当它们应该是IEnumerable时,它们会遍布整个地方.

因此,能够轻松地从一种显式集合转换到另一种显式集合在现实世界中非常有用.

重读你的陈述(目前这不是一个问题)看来你真的很困惑我们是否应该在从一个集合转换到另一个集合时需要显式的转换/转换方法.

答案就是,这取决于(而动态确实会改变一些事情,但不是很多).

简单地说,如果集合实例可以像预期类型一样被透明地处理,则不需要转换.一般来说,函数应该尝试尽可能少地请求(IEnumerable通常)然后传入的任何实际类型将通过多态性正常运行.在某些情况下,运行时必须做一些魔术来实现这一点(数组是一个值得注意的例子),但通常这很好.

事情变得复杂的地方是功能需要具体的类型.再加上糟糕的设计,比如在添加HashSet时未能包含ISet接口意味着如果你有一个真正需要一个集合的方法,你将被迫使用一个具体的类型或滚动你自己的ISet和支持Set - 不愉快.从集合到列表的某些转换操作在只读上下文中是可行的(您只是确定地枚举集合中的所有值)但不在写入上下文中(您可以向列表中添加两次但不是为例)

这就是几乎所有不可变的函数约定的有用之处,通过这样做,更容易不太关心集合的具体实现,只考虑它的外部可见行为(一组红色的黑色树或一个哈希表 - 它对消费者而言只是一个集合并不重要)

动态使事情变得有点复杂,因为保持它的实现的(粗略陈述的)'公理',当使用动态时,你应该得到与静态类型存在时相同的结果,它必须处理像数组上的运行时魔术这样的情况.