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

时间:2009-06-03 10:19:56

标签: c# design-decisions

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

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

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

2 个答案:

答案 0 :(得分:7)

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

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

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

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

  • 在2.0变更之前编写,使集合更加丰富.Net
  • 因为他们知道他们需要改变状态,所以他们会让调用者负责提供 要改变的状态(类似于排序功能的东西)
  • 他们的写得不好

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

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

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

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

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

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

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

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

答案 1 :(得分:0)

我认为Java集合框架远远优于.net one ...

例如......在Linq中,当你执行.orderBy时,你不能将它作为Icollection返回....

一切都应该从iCollection继承......

我希望收集框架在版本4上会像“类似java”