How can I avoid code duplication in C# while and do-while loops? - c#

I have a loop inside a C# method that has the following structure.
do
{
getUserInput();
if (inputIsBad)
{
doSomethingElse();
}
} while (inputIsBad);
alternately, with a while loop:
getUserInput();
while (inputIsBad)
{
doSomethingElse();
getUserInput();
}
But both methods use redundant code: the do-while has both an if statement and while loop checking the same condition; the while loop calls getUserInput() both before and inside the loop.
Is there a simple, non-redundant, non-ad hoc way to do what these method patterns do, either generally or in C# specifically, that only involves writing each basic component once?

Assuming that getUserInput(..) can be converted into a expression yielding a boolean value*..
while (getUserInput()
&& isBadInput()) {
doSomethingElse();
}
// Prompts for user input, returns false on a user-abort (^C)
private bool getUserInput() { .. }
Other variations (presumed without non-local state) shown in comments.
*Trivially, it can always be written as a wrapping function - see Local Functions, introduced in C#7. (There are other methods for the same effect, some of which I consider 'too clever'.)
// local function
bool getUserInputAlwaysTrue() {
getUserInput(); // assume void return
return true;
}
while (getUserInputAlwaysTrue()
&& isBadInput()) {
doSomethingElse();
}
This can be followed to pushing out the logic further, in some cases. The general premise holds: getUserInput() is always invoked prior to the next 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();
}

do
{
getUserInput();
if (!inputIsBad) break;
doSomethingElse();
} while (true);

I would use a boolean variable, which you need to declare outside the body of the loop. That way you only need to run the inputIsBad check once. I have turned it into a method as well, since that seems more logical.
bool badInput = true; // Assume bad until checked -- failsafe.
do
{
getUserInput();
badInput = inputIsBad();
if (badInput)
{
doSomethingElse();
}
} while (badInput);

Building on user2864740's answer:
Assume getUserInput() can be converted into a function which returns true if the input is good and bad otherwise. Assuming its original return type wasn't boolean or void, return its original return value via an out or ref parameter depending on the case, e.g.
int originalReturnValue;
while (!getUserInput(out originalReturnValue))
{
doSomethingElse();
}
...
bool getUserInput<T>(out T output)
{
// method body
}

Related

C# best practice: "break" from within Action<> callback called in a loop?

I had to write my own foreach method for various reasons. This resembles an IEnumerable foreach statement:
public void ForEachEdge(in Vertex vertex, Action<Edge> callback)
{
var edge = GetEdge(vertex.BaseEdgeIndex);
do
{
callback.Invoke(edge);
edge = GetEdge(edge.GetNext(vertex.Index));
} while (edge.Index != vertex.BaseEdgeIndex);
}
I'm using it like so but I wish to be able to "break" out of the entire loop:
ForEachEdge(edge.Vertex0Index, (e) =>
{
if (inEdge.AreConnectingSameVertices(e))
{
// break out of inner while loop here ...
}
});
What would be best practice to break?
Return a status value?
Pass a "ref bool stopEnumerating" parameter in? (requires class instance to wrap it in, right?)
Your thoughts ...
I'm mostly concerned about what end users (developers) would expect in such a case.
the ref parameter method won't be as clean as a return value indicating continuation status. You would have to switch to a Func<Edge, bool>
Func<Edge, bool> callback;
...
if (callback.Invoke(edge)) {
/// do your break logic
}
I decided that (for now) I'll go with a Predicate<> rather than Action<>:
public void ForEachEdge(in Vertex vertex, Predicate<Edge> callback)
{
var edge = GetEdge(vertex.BaseEdgeIndex);
do
{
if (callback.Invoke(edge))
break;
edge = GetEdge(edge.GetNextRadialEdgeIndex(vertex.Index));
} while (edge.IsValid && edge.Index != vertex.BaseEdgeIndex);
}
Which makes the user's code look like this:
ForEachEdge(edge.Vertex0Index, e =>
{
if (inEdge.AreConnectingSameVertices(e))
{
// found it, do something, then exit loop
return true;
}
// continue with next item
return false;
});
The nicest thing about this solution: both Predicate<> and Action<> variants can exist side-by-side! User either returns true/false from the predicate, or does not return anything and thus uses the Action<> version, like so:
ForEachEdge(edge.Vertex0Index, e =>
{
if (inEdge.AreConnectingSameVertices(e))
{
// do stuff
}
});
Purrfect! :)

Which solution is best for breaking from a loop on user input?

I am currently learning programming and often I stumble upon tasks where you type into the console indeterminate amount of lines (each is a command that I have to filter out later in main with a switch or if-else statements) and at the end you type "END" to say that you will stop writing lines (often it results in end of the program but sometimes I have to print some final code). For the longest time I have used this solution to choose the needed selection:
while (true) {
var input = Console.ReadLine().Split();
if (input[0] == "END") break;
switch (input[0]) {
//Task specific cases
}
}
but today I randomly had an idea. (After I did some research) I could add the "END" case in the switch statement using the word return. The only problem is that because my code is in main it automatically ends the program. The solution is to transfer the code to another method but is this solution better or is it a bit overcomplicated?
*Here is what the second solution looks like:
static void Main(string[] args) {
Logic();
//Other stuff to do, if the task requires it
}
public static void Logic() {
while (true) {
var info = Console.ReadLine().Split();
switch (info[0]) {
case "END": return;
//Other task specific cases
}
}
}
**Sorry if the post is confusing to read, I am not very good with programming terminology.
This is another possible implementation:
public static void Logic()
{
bool exit = false;
do
{
var info = Console.ReadLine().Split();
switch (info[0])
{
case "END":
exit = true;
break;
}
}
while (!exit);
}
Any of the solutions, to use break or to return are correct, but have different behaviors. You can use the one that you find is better.
The break statement is used to terminate the loop or statement in
which it present. After that, the control will pass to the statements
that present after the break statement, if available. If the break
statement present in the nested loop, then it terminates only those
loops which contains break statement.
The return statement terminates the execution of the method and
returns the control to the calling method. It returns an optional
value. If the type of method is void, then the return statement can be
excluded.
You can read more here: https://www.geeksforgeeks.org/c-sharp-jump-statements-break-continue-goto-return-and-throw/

Try-catch until success - execution loop for generic methods or delegates

I want my code to keep trying a method until no exception is thrown, however, unlike this question, I would like it to be written as a generic method capable of running any input delegate/method. Here is what I've had in mind, but I am not sure how to pass the arguments or generic methods through it:
public void tryLoop(Delegate anyMethod, T[] arguments) {
while (true) {
// Could be replaced by timer timeout
try {
anyMethod(arguments);
break;
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
Is this possible?
EDIT: For the academics of it, I would also be curious to know if it's possible to return the result as well.
If you can settle for using closures, you won't need to have to pass parameters to this method all (or have multiple overloads). The result can be returned using a Func.
public T tryLoop<T>(Func<T> anyMethod)
{
while (true)
{
try
{
return anyMethod();
}
catch
{
System.Threading.Thread.Sleep(2000); // *
}
}
return default(T);
}
void SomeMethod(int param)
{
var someLocal = "Hi";
var anotherLocal = 0;
var result = tryLoop(() =>
{
Console.WriteLine(someLocal);
return param + anotherLocal;
});
Console.Write(result);
}
To be honest, I wouldn't set an infinite retry, however - at best, if certain types of retryable error were returned, such as a database deadlock, or a timeout calling an erratic web service, then possibly 3 or 4 retries might be in order. Exceptions such DivideByZero or FileNotFound aren't likely to go away by running them indefinitely :-)
*** especially with deadlocks, sleeping for a random period is recommended, just in case other threads are also simultaneously deadlocking on exactly the same data - you don't want the same deadlock recurrence happening in 2000ms :-).
A way to do this is by using an Action, and remove the arguments parameter:
public void tryLoop(Action anyMethod) {
while ( true ) {
// Could be replaced by timer timeout
try {
anyMethod();
break;
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
This gives you ultimate freedom in how to use it:
tryLoop(() => string.Reverse("abc"));
or like this:
String s1 = "A";
String s2 = "b";
tryLoop(() => string.Concat(s1, s2));
As you can see in the second example, you can directly take the arguments from the context of the tryLoop method being called. You can invoke anything there.
The good thing for this approach is that you will not have to use Invoke or DynamicInvoke as with a Delegate instead of Action, because these introduce a performance penalty.
If you need the result, you can re-write the above with a Func<T> instead of Action, like this:
public T tryLoop<T>(Func<T> anyMethod) {
while ( true ) {
// Could be replaced by timer timeout
try {
return anyMethod();
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
and use it like this:
var reversed = tryLoop(() => string.Reverse("abc"));
String s1 = "A";
String s2 = "b";
var concatenated = tryLoop(() => string.Concat(s1, s2));
Check if this suit your needs. If not then please comment. Also not sure how it will be performance wise.
Also the DynamicInvoke method has an object return type. This you can use to return the result of the delegate. You can change the return type of method from void to object.
public void tryLoop<T>(Delegate anyMethod, T[] arguments)
{
while (true)
{ // Could be replaced by timer timeout
try
{
anyMethod.DynamicInvoke(arguments);
break;
}
catch
{
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
Hope this helps

C# Function Return Error

I'm new to C# and while coding a small function facing this weird problem. While using the return statement I want to return to the calling function but instead it takes me to a level before in the recursion and never exits from the recursive function.
My code is as follows:
private void findrel(String from, String to, List<RelAttr> relation)
{
String var;
List<RelAttr> temp = new List<RelAttr>();
for (int i = 0; i < relation.Count; i++)
{
if (Some Condition)
{
if (Another Condition)
{
//Do Something
paths.Add(Something);
return;
}
else
{
//Capture some value in var
paths.Add(Something);
//Move to Temp
temp.AddRange(relation);
//Remove Active Entry From Temp
temp.RemoveAt(i);
//Call with Newlist (temp)
findrel(var, to, temp);
}
}
}
//Remove Last Entry when recursion unwinds
paths.RemoveAt(paths.Count - 1);
}
I'm calling this function normally from the other function such as:
findrel(from, to, relations);
And I want the return statement to return to this function and not to a level before in the recursion. Any ideas?
The return statement will always return to the caller, and when you are using recursion this will include returning to the level above, and will not jump back to the original caller.
If you want to get right out of findrel then you will have to do something like return a flag so that the previous level knows that it should just return back to its caller and not do any more processing.
So the code will still unwind from all the calls to findrel but you will have effectively stopped processing.
Usually with recursive functions you have a terminating condition and that causes all levels of the returning function to return and this will return you to the caller. One suggestion might be to return a Boolean and terminate the recursion if that value is say false. The you can add that condition to the terminating condition of your loop and your function will exit all levels.

Use of return keyword in code block

What is the difference between saying:
if (abc == "a")
{
// do something here...
return;
}
and the same as above, but without the return keyword?
I am a C# coder and I know that the return keyword followed by a type or variable returns that item, but in the above context, return seems to be just to exit the code block but does it make any functional or performance change on the code?
Thanks
"return" exits from the function, not just the enclosing code block. So if your code block was in the context of a function, like so (I don't know C# so I'm using Java syntax):
int thisIsAFunction(int a) {
if (abc == "a")
{
// do something here...
return 1;
}
// do something else here...
}
if abc == "a" then the "do something else here" will not run. But if you removed the return statement inside the if block, then it would run.
return statement exits the function immediately, so it might have performance benefits as the following code in the function would not be executed at all.
MSDN
The return statement terminates execution of the method in which it appears and returns control to the calling method. It can also return an optional value. If the method is a void type, the return statement can be omitted.
Example
//this would do nothing
public void method()
{
return;
}
//this would return true
//notice the return type of bool this means
//the method expects a true\false value
public bool method2()
{
return true;
}
public void test()
{
if(method2())
method()
}
Now if you ran test method2 would always return true and method1 would just end its processing
The return statement does exit the current method, not just the code block (for/while/if/etc). So it is useful for situations like the following:
public void MyMethod(object myObject)
{
if (myObject == null)
{
return; // exits method.
}
// do something with myObject
}
Additional info: I will point out, that many people prefer to have one exit point in a method, however, it can be useful to do something similar to the example here in some cases. I would always try to find ways to limit the number of return or exit points in your method.
In your case, no - but if you had other code after your 'if' statement that you only wanted to run if your statement was false (e.g. if abc != "a"), then the return allows you to bypass that and exit the function / method.
In a loop or case statement, you can use break to achieve this result. This doesn't work on if statements or code blocks in general though.
And yes, return exits the enclosing function.
Executing the return statement will make the execution jump out of the method. Without the return, it would simply go on with the next statement instead.
Yes, your method does not have return type in this case.
e.g.
public void Foo
{
if (abc == "a")
{
// do something here...
return;
}
// some other code
}
This is to say if abd = "a", then exit the method so that some other code won't be executed.
It can be a cleaner way of writing code. I typically do it in a guard clause at or near the beginning of a method. If you have an error condition, just "return" out of the method. It saves wrapping the rest of your work in an else block. Seems trivial, but it helps to reduce code complexity.

Categories

Resources