让 C# 编译器相信执行将在成员返回后停止

问题描述 投票:0回答:5

我认为目前这是不可能的,或者这是否是一个好主意,但这是我刚才正在考虑的事情。 我使用 MSTest 对我的 C# 项目进行单元测试。 在我的一项测试中,我执行以下操作:

MyClass instance;

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

instance.doStuff(); // Use of unassigned local variable 'instance'

为了使此代码编译,我必须在其声明处或在

instance
块中为
catch
分配一个值。 我也可以在
return
之后
Assert.Fail
但这仍然是一种解决方法,而不是编译器只是 知道 在这一点之后执行无法继续。 据我所知,
Assert.Fail
永远不会允许执行继续进行,因此
instance
永远不会在没有值的情况下使用。 那么为什么我必须给它赋值呢? 如果我将
Assert.Fail
更改为类似
throw ex
的内容,代码可以正常编译,我认为是因为它知道异常将不允许执行继续到
instance
未初始化时使用的点。

相反,如果我不想让测试失败,而是希望被标记为不确定怎么办? 我可以做一个

Assert.Inconclusive
而不是
Fail
,如果编译器知道执行之后不会继续,那就太好了。

那么这是运行时与编译时关于允许执行的位置的知识的情况吗? 对于 C# 来说,以某种方式表示某个成员(在本例中为

Assert.Fail
)在返回后永远不会允许执行是否合理? 也许这可以是方法属性的形式。 这对编译器来说有用还是不必要的复杂性?

外部单元测试

既然人们[有效地]指出这是一种编写单元测试的愚蠢方法,请在单元测试领域之外考虑我的问题:

MyClass instance;

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

instance.doStuff();

这里我可能可以用抛出异常来替换对

someMethodThatWillNeverReturn
的调用,也许如果我有事情要做,我可以在异常的构造函数中完成它。

Resharper 知道

如果我在

return
Assert.Fail
之后添加
Assert.Inconclusive
,Resharper 颜色为
return
灰色,并有一个工具提示显示“代码试探性无法访问。”

c# runtime execution compile-time
5个回答
3
投票

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

您希望有某些东西(无论是在 CLR 中还是在编译器中)来制定一个备份计划,以防万一您出错了:如果有人更改

Assert.Fail
以正常返回,会发生什么?您可能希望代码验证的一部分是检查它永远不会正常返回的内容。

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

就表示它的语法而言,虽然属性是一个显而易见的想法,但我非常喜欢“never”返回类型的想法。显然,这可能会与现有的“从不”类型发生冲突,但是嘿......

就其有用性而言:明显的解决方法是在语句之后立即抛出异常,但必须这样做确实很烦人。 (它通常比返回更好,因为这意味着如果您编写的方法具有返回类型,则不必指定无意义的返回值 - 并且您也不需要确保所有

out 
参数被赋值。)所以它不是 required - 但我认为这会很好。这是否是 C# 团队在有限的预算下能做的最重要的事情是另一回事 - 只是为了先发制人 Eric ;)


1
投票

throw ex
之后
Assert.Fail
?或者,更好的方法是,在这种情况下完全删除
try/catch
Assert.Fail
,并让未捕获的异常让您的单元测试失败。


1
投票

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


0
投票

return
之后
Assert.Fail()


0
投票

看到你在抛出的异常上断言失败,为什么不将整个测试移到try中,或者摆脱try并让抛出的异常自动断言失败。

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

...或...

MyClass instance;
instance = MyClass.getValue();
instance.doStuff();
© www.soinside.com 2019 - 2024. All rights reserved.