【问题标题】:Is there ever an excuse for throwing an Exception from an implicit conversion?从隐式转换中抛出异常是否有任何借口?
【发布时间】:2025-12-09 21:45:01
【问题描述】:

来自MSDN

通过消除不必要的强制转换,隐式转换可以提高源代码的可读性。然而,因为隐式转换可以在程序员没有指定的情况下发生,所以必须注意防止令人不快的意外。一般来说,隐式转换操作符不应该抛出异常,也不应该丢失信息,以便在程序员不知情的情况下安全地使用它们。如果转换运算符不能满足这些条件,则应将其标记为显式。

虽然我不反对任何特定的观点,并且我同意这一切都非常好,但是否有足够的理由来保证打破关于隐式转换不引发异常的部分?

我面前的特殊情况是:

  1. 我有一个函数,它返回一个自定义集合对象(我们称之为FooCollection)。
  2. 这个函数可以返回单个项目的集合,可以从源代码中判断是否会发生这种情况。 (这里我的意思是函数调用,而不是函数本身)
  3. 如果确实发生了,那么用户有 99.9% 的可能性想要该单个项目,而不是包含单个项目的集合。

现在,我正在考虑是否包含来自 FooCollection => Foo 的隐式转换以隐藏这个小的实现细节,但这种转换只有在集合中有单个项目时才有效。

在这种情况下可以抛出Exception 吗?或者我应该使用显式强制转换吗?关于如何处理这个问题的任何其他想法(不,由于实现细节我不能只使用两个函数)?

编辑:我觉得值得注意的是FooCollection 没有实现任何接口或实际上扩展Collection,正如名称所暗示的那样,因此基于LINQ 的答案是无用的。此外,虽然集合确实实现了数字索引,但它并不是处理集合的最直观方式,因为它主要依赖于命名索引。

【问题讨论】:

    标签: c# casting implicit explicit


    【解决方案1】:

    我同意准则:您永远不应该从隐式转换中抛出。

    在这种情况下,我绝对不会提供隐式转换。即使是明确演员的想法对我来说也是错误的:Foo x = (Foo)fooCollection 似乎并不正确。

    为什么不让调用代码担心从FooCollectionFoo 的转换?代码对每个人来说都会更直观:

    Foo a = fooCollection[0];
    Foo b = fooCollection.First();
    Foo c = fooCollection.FirstOrDefault();
    // etc
    

    【讨论】:

    • Foo x = (Foo)fooCollection 也不会是“正确的”(尽管它会编译)。 Foo x = (Foo)fooCollection.x() 将是它的使用方式。
    • x() 是一个从 fooCollection 返回 1 项子集的函数。
    • 不管怎样,你仍然试图将Foo 的一些集合转换为Foo 本身,这让我感觉很奇怪。为什么不让调用代码执行Foo x = fooCollection.x()[0] 或类似的操作?
    • 除其他外,感觉很乱。但是从隐式转换中抛出异常也感觉不对。哦,好吧,我想 SO 无论如何都说过:)
    • 我的说法略有不同:任何在执行隐式转换时抛出的对象实例都应该被视为损坏。如果例如一个非线程安全的对象实例由于多个线程的同时操作而损坏,该实例可能适合在通常会扩大类型转换的情况下抛出异常,但只是因为实例已损坏 i>.
    【解决方案2】:

    显然不行。 永远不要使用异常来实现逻辑!

    您可以使用 Linq-Statement FooCollection.FirstOrDefault(),它将给出 null 或第一项。

    【讨论】:

      【解决方案3】:

      演员表应该是明确的。能够在没有强制转换的情况下将 FooCollection 分配给 Foo 会很奇怪。

      话虽如此,恕我直言,演员表并不是一个好方法。即使你拒绝,我也会使用一个函数,因为即使你无法控制这些类的实现,你至少可以添加像 Foo ToFoo(this FooCollection collection) 这样的扩展方法来完成工作。

      【讨论】:

      • 我实际上有 50% 的把握这也行不通,因为这是在 C# 4.0 和动态类型的上下文中
      • 即。我不确定动态路由是否考虑了扩展方法。该死的,现在我有别的东西我想试试!
      【解决方案4】:

      仅当集合中只有 1 个项目时才起作用的隐式 copnversion?那么,事实上,它大部分时间都不起作用?

      我永远不会隐含这种转换。坚持显式。如果使用你的函数的程序员想要拥有单个项目,他应该告诉你的班级。

      【讨论】: