提问人:Jacob Archambault 提问时间:1/26/2020 更新时间:2/1/2020 访问量:543
如何避免 C# while 和 do-while 循环中的代码重复?
How can I avoid code duplication in C# while and do-while loops?
问:
我在 C# 方法中有一个循环,该方法具有以下结构。
do
{
getUserInput();
if (inputIsBad)
{
doSomethingElse();
}
} while (inputIsBad);
或者,使用 while 循环:
getUserInput();
while (inputIsBad)
{
doSomethingElse();
getUserInput();
}
但这两种方法都使用冗余代码:do-while 同时具有 if 语句和 while 循环检查相同的条件;while 循环在循环之前和循环内部都调用 getUserInput()。
有没有一种简单、非冗余、非临时的方法来执行这些方法模式所做的事情,无论是一般的还是专门在 C# 中,只涉及编写每个基本组件一次?
答:
2赞
user2864740
1/26/2020
#1
假设可以将其转换为生成布尔值的表达式*。getUserInput(..)
while (getUserInput()
&& isBadInput()) {
doSomethingElse();
}
// Prompts for user input, returns false on a user-abort (^C)
private bool getUserInput() { .. }
注释中显示的其他变体(假定没有非本地状态)。
*微不足道的是,它始终可以编写为包装函数 - 请参阅 C#7 中引入的局部函数。(还有其他方法可以达到同样的效果,其中一些我认为“太聪明了”。
// local function
bool getUserInputAlwaysTrue() {
getUserInput(); // assume void return
return true;
}
while (getUserInputAlwaysTrue()
&& isBadInput()) {
doSomethingElse();
}
在某些情况下,可以遵循这进一步推出逻辑。一般前提是:总是在下一个之前调用。getUserInput()
isBadInput()
// local function or member method
// Prompt for user input, returning true on bad input.
bool getCheckedUserInput() {
getUserInput(); // assume void return
return isBadInput();
}
while (getCheckedUserInput()) {
doSomethingElse();
}
0赞
rossum
1/27/2020
#2
我将使用一个布尔变量,您需要在循环主体外部声明该变量。这样,您只需要运行一次检查。我也把它变成了一种方法,因为这似乎更合乎逻辑。inputIsBad
bool badInput = true; // Assume bad until checked -- failsafe.
do
{
getUserInput();
badInput = inputIsBad();
if (badInput)
{
doSomethingElse();
}
} while (badInput);
评论
0赞
Jacob Archambault
1/31/2020
这包含与原始问题中首次声明的版本相同的冗余,同时添加了不必要的代码:布尔值仍在由 if 语句和 while 循环的条件检查,而对 badInput 的初始赋值从未使用(因为变量在检查之前在 do-while 循环中被重新赋值)。
0赞
rossum
1/31/2020
此版本仅运行一次。这大概比简单的布尔检查需要更长的时间。您的初始版本运行了两次。inputIsBad()
2赞
Kahou
1/27/2020
#3
do
{
getUserInput();
if (!inputIsBad) break;
doSomethingElse();
} while (true);
评论
1赞
Jacob Archambault
1/31/2020
尽管我发现哨兵是临时的,但这种通用的解决方案很简单,易于阅读,并且消除了原始帖子中的代码重复。
1赞
Jacob Archambault
1/31/2020
一个小问题:将 while 设置为 true 实际上使“do”变得不必要,因此可以通过将其转换为 while 循环来进一步简化。
0赞
Jacob Archambault
2/1/2020
#4
基于 user2864740 的回答:
假设 getUserInput() 可以转换为一个函数,如果输入是好的,则返回 true,否则返回 true。假设其原始返回类型不是布尔值或 void,则根据大小写通过 out 或 ref 参数返回其原始返回值,例如
int originalReturnValue;
while (!getUserInput(out originalReturnValue))
{
doSomethingElse();
}
...
bool getUserInput<T>(out T output)
{
// method body
}
评论
X v; while ((v = getUserInput()) != null /* assumes sentinel for boolean */ && isInputBad(v)) { doSomethingElse(v); }
&&
&&
v
while(isInputBad(v = getUserInput()) { doSomethingElse(v); }