说服C#编译器在成员返回后执行将停止

我不认为这是目前可行的,或者它是否是一个好主意,但这是我刚才想到的。 我使用MSTest对我的C#项目进行unit testing。 在我的一个测试中,我执行以下操作:

MyClass instance; try { instance = getValue(); } catch (MyException ex) { Assert.Fail("Caught MyException"); } instance.doStuff(); // Use of unassigned local variable 'instance' 

为了使这段代码编译,我必须在其声明或catch块中为instance赋值。 我可以选择在Assert.Fail之后return ,但这仍然是一种解决方法,而不是编译器只知道在此之后执行无法继续。 Assert.Fail永远不会,据我所知,允许执行继续它,因此instance永远不会没有值。 那为什么我必须给它赋值? 如果我将Assert.Fail更改为类似throw ex ,则代码编译正常,我假设因为它知道exception将禁止执行进入instance将未初始化使用的点。

相反,如果我不希望测试失败,而是标记为不确定,该怎么办? 我可以做一个Assert.Inconclusive而不是Fail ,如果编译器知道之后执行不会继续,那就太好了。

那么运行时与编译时知识的情况是否允许执行在哪里进行? C#是否有理由说某个成员(在这种情况下是Assert.Fail在返回后永远不允许执行? 也许这可能是方法属性的forms。 这会对编译器有用还是不必要的复杂性?

外部unit testing

由于人们[有效]指出这是编写unit testing的愚蠢方式,因此请考虑我在unit testing领域之外的问题:

 MyClass instance; if (badThings) { someMethodThatWillNeverReturn(); } else { instance = new MyClass(); } instance.doStuff(); 

在这里,我可能会将someMethodThatWillNeverReturn的调用替换为抛出exception,也许如果我有事可做,我可以在exception的构造函数中执行此操作。

Resharper知道

如果我在Assert.FailAssert.Inconclusive之后添加一个return ,Resharper颜色将return灰色并且有一个工具提示,上面写着“Code is heuristically unreachable”。

是的,有一些东西表明一个成员永远不会正常完成是合理的 – 即断言成员之后的点是无法到达的。 (这可能是由于exception或由于永远循环造成的。)

如果你错了,你想要有东西 (无论是在CLR还是编译器中)来制定备份计划:如果有人改变了Assert.Fail以便正常返回会发生什么? 您可能希望部分代码validation成为检查它永远不会正常返回的东西。

我相信有一篇关于这个想法的博客文章来自微软的某个人…我会看看我是否能找到它。

在表示它的语法方面,虽然属性是一个明显的想法,但我非常喜欢返回类型为“never”的想法。 显然这可能会与现有的“从不”类型发生冲突,但嘿……

就其用途而言:显而易见的解决方法是在语句之​​后立即抛出exception,但必须这样做肯定很烦人。 (它通常比返回更好,因为这意味着如果您正在编写此方法的方法具有返回类型,则不必指定无意义的返回值 – 并且您也不需要确保所有out参数分配值。)所以它不是必需的 – 但我认为它会很好。 C#团队在预算有限的情况下能做的最重要的事情是另一回事 – 只是为了抢占Eric;)

Assert.Fail之后throw ex ? 或者,更好的是,在这种情况下完全删除try/catchAssert.Fail ,并让未捕获的exception为您进行unit testing失败。

我想知道的一件事:如果您手动编译并执行它,运行时如何处理此代码? 我相信它会检查IL代码中的错误,也许它会抓住这个“错误”……也许不是:)

Assert.Fail()之后return

看到你在抛出exception时断言失败,为什么不将整个测试移动到try中,或者除掉try并让抛出的exception自动断言失败。

 try { MyClass instance; instance = MyClass.getValue(); instance.doStuff(); } catch (Exception ex) { Assert.Fail("Caught MyException"); } 

… 要么 …

 MyClass instance; instance = MyClass.getValue(); instance.doStuff();