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

发布于 2024-08-26 14:40:47 字数 1492 浏览 8 评论 0原文

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

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 之类的内容,则代码可以正常编译,我假设是因为它知道异常将不允许执行继续到 >instance 将在未初始化的情况下使用。

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

那么这是运行时与编译时关于允许执行的位置知识的情况吗?对于 C# 来说,以某种方式表示成员(在本例中为 Assert.Fail)返回后永远不会允许执行是否合理?也许这可以是方法属性的形式。这对于编译器来说是有用的还是不必要的复杂性?

外部单元测试

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

MyClass instance;

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

instance.doStuff();

这里我可能可以替换对 someMethodThatWillNeverReturn 抛出异常,也许如果我有事情要做,我可以在异常的构造函数中完成它。

Resharper 知道

如果我在 Assert.FailAssert.Inconclusive 之后添加 return,Resharper 会为 return 着色 灰色,并有一个工具提示“代码试探性无法访问”。

I don't think this is currently possible or if it's even a good idea, but it's something I was thinking about just now. I use MSTest for unit testing my C# project. In one of my tests, I do the following:

MyClass instance;

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

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

To make this code compile, I have to assign a value to instance either at its declaration or in the catch block. I could alternatively return after the Assert.Fail but that's still a workaround instead of the compiler just knowing that execution cannot continue after this point. Assert.Fail will never, to the best of my knowledge, allow execution to proceed past it, hence instance will never be used without a value. Why is it then that I must assign a value to it? If I change the Assert.Fail to something like throw ex, the code compiles fine, I assume because it knows that exception will disallow execution to proceed to a point where instance would be used uninitialized.

Contrariwise, what if I didn't want the test to fail, but rather be marked as inconclusive? I could do an Assert.Inconclusive instead of Fail, and it would be nice if the compiler knew execution would not continue after that.

So is it a case of runtime versus compile-time knowledge about where execution will be allowed to proceed? Would it ever be reasonable for C# to have some way of saying that a member, in this case Assert.Fail, will never allow execution after it returns? Maybe that could be in the form of a method attribute. Would this be useful or an unnecessary complexity for the compiler?

Outside Unit Tests

Since people are [validly] pointing out that this is a silly way to write a unit test, consider my question outside the realm of unit testing:

MyClass instance;

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

instance.doStuff();

Here potentially I could replace the call to someMethodThatWillNeverReturn with throwing an exception, and perhaps if I had stuff to do, I could do it in the constructor for the exception.

Resharper Knows

If I add a return after Assert.Fail or Assert.Inconclusive, Resharper colors return gray and has a tooltip saying "Code is heuristically unreachable."

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

审判长 2024-09-02 14:40:47

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

如果您错了:如果有人将 Assert.Fail 更改为正常返回,会发生什么情况?您可能希望代码验证的一部分是检查它永远不会正常返回的内容。

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

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

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

Yes, it would be reasonable to have something which indicated that a member would never complete normally - i.e. asserting that the point after the member was unreachable. (This could either be due to an exception or due to looping forever.)

You'd want there to be something (whether in the CLR or the compiler) to come up with a backup plan for if you're wrong: what would happen if someone changed Assert.Fail to return normally? You'd potentially want part of code verification to be something that checked it would never return normally.

I believe there's a blog post about this idea from someone in Microsoft... I'll see if I can find it.

In terms of syntax for representing it, while an attribute is an obvious idea, I quite like the idea of a return type of "never". Obviously that would potentially clash with existing "never" types, but hey...

In terms of its usefulness: the obvious workaround is to throw an exception immediately after the statement, but it's certainly annoying to have to do that. (It's generally better than a return as it means if the method you're writing this in has a return type, you don't have to specify a pointless return value - and you also don't need to make sure that all out parameters are assigned values.) So it's not required - but I think it would be nice. Whether it's the most important thing the C# team can do with their limited budget is a different matter - just to pre-empt Eric ;)

小女人ら 2024-09-02 14:40:47

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

throw ex after Assert.Fail? Or, better, just remove the try/catch and Assert.Fail entirely in this case, and let the uncaught exception fail the unit test for you.

岁月蹉跎了容颜 2024-09-02 14:40:47

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

One thing I'm wondering about: How would the runtime treat this code if you'd manually compile and execute it? I believe it checks for errors in the IL code, maybe it catches this "error" as well... maybe not :)

给我一枪 2024-09-02 14:40:47

Assert.Fail() 之后返回

return after Assert.Fail()

傲影 2024-09-02 14:40:47

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

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

... 或者 ...

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

Seeing that you are asserting Fail on a thrown exception, why don't you either move the entire test into the try, or get rid of the try and let the thrown exception automatically Assert fail.

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

... or ...

MyClass instance;
instance = MyClass.getValue();
instance.doStuff();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文