C#方法命名规范:ToSomething与AsSomething的区别

85

当我为我的业务逻辑对象编写扩展方法时,我遇到了一个问题:如何更改转换方法的名称。someObject.ToAnotherObject() 与广泛使用的 object.ToString() 相似。

但是,例如LINQ混合使用这两种变体,我找不到它们之间的区别。 ToDictionary()ToList()AsParallel()AsQueryable()等方法都采用了这种命名方式。

这两种命名约定有什么区别,我应该知道什么来决定是否在自己的类中使用这种方式?

2个回答

94

ToDictionaryToList 的前缀是 To,因为它们不一定会保留原始集合的结构标识或其特性。

  • List<T> 转换为 Dictionary<K, V> 会创建一个具有全新结构的集合。
  • HashSet<T> 转换为 List<T> 将移除集合的唯一性属性。

带有 As 前缀的方法不会执行这些操作 - 它们只是提供原始集合的另一种 视图。它们丰富它。


42
所以,对于一个苹果,我可以调用 .AsCleanApple() 来表示我只需要清洗它,而调用 .ToFruitSalad() 则意味着我的刀会改变苹果的结构吗? - Physikbuddha
3
基本上,是的。 - MKII
38
@Physikbuddha 对我来说,AsCleanApple似乎会改变苹果的某些方面。更好的类比可能是AsFruit - dcastro
4
.AsCleanAppleSource() 的作用是将原本提供苹果的来源变成提供干净苹果的来源;如果需要,会添加清洗步骤,但如果已知苹果已经很干净了,则可能什么都不做。.ToPunnet() 则可以获取这个来源并为你提供一篮苹果。 - Jon Hanna
3
严格来说,这并不完全正确,但通常你可以把 "AsXXX()" 理解为强制类型转换(cast),而把 "ToXXX()" 理解为类型转换(conversion)。 - nateirvin
如果我将IEnumerable<T>转换为IEnumerable<U>,其中T可以隐式转换为T,那么这是ToU还是AsU?或者这是否取决于我在方法中是否实际枚举输入? 当有人枚举我的方法的结果时,隐式转换将为每个项目创建新的U实例。 我很难确定我是否会改变IEnumerable<T>的“结构标识”。 - comecme

26
在 Linq 中,ToXXX 方法会执行查询并从结果中创建一个新对象,而 AsXXX 方法则会生成一个不同的查询。它可能是相同的对象,但通过不同的接口访问(AsEnumerable() 这样做),或者它可能是修改功能的新对象(其他方法这样做,尽管有些方法会检查是否可以返回给定的对象,例如,如果源已实现 IQueryable<T>,则 AsQueryable() 将返回 source,否则将创建一个新的 EnumerableQuery<TElement>)。

“that alters how the functionality” - “how”是否不必要,还是应该有下一部分陈述? 这句话中的“how”是否必要,还是需要进一步说明? - Kapol
@Kapol 不是的,只是同时组合和打字导致的笔误。 - Jon Hanna
我认为这是正确的答案,即原始实例的活动投影与静态投影。 ToXXX() 投影数据与原始数据没有关系。AsXXX() 保持与原始数据的活动关系(至少在我们讨论的 Enumerable/Queryable 示例中)。 - Tim M.
+1 表示 ToXXX 执行查询,而 AsXXX 生成新的查询。从我在 LINQ 上阅读的内容来看,这听起来是正确的,而且 MSDN 似乎也证实了 ToXXX 的情况,但我想知道是否所有的 AsXXX 方法都是延迟执行的? - brichins
1
@brichins,是否有一种有意义的方式来表示“所有”?因为我们中的任何一个人都可以使用新提供程序添加到 Linq 中固有的 AsXXX 之上(例如 PLinq 添加的 AsParallel,Entity Framework 提供的 AsNoTracking 等)。当然,Linq 的核心是由 QueryableEnumerable 定义的,这两个类都遵循该约定。大多数附加功能也是如此,到了某种程度上,“所有”可能是正确的,但它太开放了,不能保证始终正确(尽管我认为任何破坏都是设计缺陷)。 - Jon Hanna
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接