C# loop over bool values
Asked Answered
S

5

9

Is there a concise way to loop over true/false in C#?

I have ~20 lines of code in a unit test I'd rather not duplicate to toggle one boolean true/false.

I could break it off into a function and call it twice, but meh. This code feels more like I'm iterating over possible values than performing a distinct action with different parameters. Even if I had a function, I'd prefer the syntax of looping over the possible values rather than just calling it twice.

I could write a for loop like so...

bool toggle;
for (int i = 0; i < 2; i++)
{
    toggle = i == 1;
}

But that doesn't seem very clean.

I like this syntax:

for (bool b : { false, true }) { /* ... */ }

But it doesn't look like that will compile in C#.

Edit:

Following Jeroen's suggestion about local functions and Dmitry's answer, this is the route I went:

[TestMethod]
public void GetAndSetValue()
{
    foreach (bool toggle in new [] { false, true })
    {
        GetAndSetValue(toggle);
    }

    void GetAndSetValue(bool toggle)
    {
        // details not important
    }
}

Reasonable coders can debate whether the loop reads more easily than two function calls:

GetAndSetValue(false);
GetAndSetValue(true);

I like the loop better, so I'll roll with it until someone complains. Cheers!

Sterculiaceous answered 4/7, 2018 at 14:28 Comment(11)
foreach (bool b in new bool[] { false, true }) {...}Latticework
I really don't get why you think extracting this code into it's own function is a bad idea. For me, creating the loop as per Dmitry's answer is more complicated and less readable.Mosquito
new[] { true, false }.ToList().ForEach(b => Console.WriteLine(b));Wreath
@Mosquito even if I extracted to a function, writing the function call twice feels less expressive (correct term?) than looping over possible values.Sterculiaceous
To add to what David said, don't forget that recent versions of C# have local functions, essentially making extracting such code free. Calling a function twice would be much more intuitive to me than "looping over every boolean", which would cause me to do a double take, even if it happens to semantically be what you're doing, simply because it's not usually the sort of thing you loop over. It's like looping over every possible even prime.Nonbelligerent
Why? I completely disagree with that I'm afraid. DoStuff(true) and DoStuff(false) looks a lot nicer than a for loop. The cognitive load to parse out what the loop is doing is surely not worth the effort.Mosquito
@Mosquito matter of opinion, I guess... I would read that as "do a thing, then do a different thing" vs. "do all the relevant things." But like I say, my brain may be unique in that way.Sterculiaceous
I like the loop better, so I'll roll with it until someone complains. - I am complaining so stop it. :)Bornie
@RandRandom yeah but you're just like... some random someone. :-PSterculiaceous
I agree with the OP that the true and false call is an ugly solution. For one thing is impossible to see if it could have been called with other values also. It is much cleaner to define the possible input set, and then a foreach over that. preferably in a named local variable to ease readability on what we are looping over. Had it been an enum we could use .GetValues. Unfortunately that is not supported by bool. (the funktion MIGHT work on say a tri-state, that implicitly converts from bool like True/False/NA and you would never know that the third option was never tested)Godoy
(... or the bool? type, with null as the third possible input).Godoy
L
22

Correct syntax will be foreach, not for:

foreach (bool b in new [] { false, true }) {
   /* ... */
}
Latticework answered 4/7, 2018 at 14:29 Comment(8)
I like it. Not quite as pretty as the C++ version. And I wish it somehow expressed perfectly explicitly that false once and true once are the only values this loop is ever intended to iterate over. i.e. no one could at a glance think, "I could totally add ten more trues and falses to this list". But now I'm really just being pedantic. :-PSterculiaceous
For a moment you had an edit with a for loop... what was wrong with that implementation?Sterculiaceous
@mac9416: I doubt if I should have posted such unreadable for (bool b = false; !b; b = true) {/*....*/} even for reference only.Latticework
Yes, obviously that should have been for (bool b = false; !b; b = !b)... :-PNonbelligerent
Oddly, I find it elegant. But probably in the same way I find a prop plane more elegant than a 737 - nerdiness. Agreed, foreach is more readable. Thanks!Sterculiaceous
Elegant or not, it doesn't actually work -- it only produces false. There's no concise way to do this with a for loop.Nonbelligerent
for (bool? b = false; b != null; b = (b.Value ? (bool?)null : true)) ... I know, it's horrific. Just couldn't help myself.Sterculiaceous
To avoid continual array allocation, I'd put the collection at the class-level like so: private static readonly IEnumerable<bool> _Booleans = new[] { false, true }; and then your loop looks like foreach (bool b in _Booleans) {.Scattering
L
4

While I think simply writing a parametrized function is definitely the correct approach, the closest to that C++11 syntax that you can get in C# would be:

foreach (bool value in new [] { false, true })
{
    // ...
}
Loraleeloralie answered 4/7, 2018 at 14:32 Comment(0)
B
1

I would probably just do it this way, either with a local function:

[TestMethod]
public void GetAndSetValue()
{
    GetAndSetValue(false);

    void GetAndSetValue(bool toggle)
    {
        // details not important

        if (!toggle)
            GetAndSetValue(true);
    }
}

Or "old" school with a private method.

[TestMethod]
public void GetAndSetValue()
{
    GetAndSetValue(false);
}

private void GetAndSetValue(bool toggle)
{
    // details not important

    if (!toggle)
        GetAndSetValue(true);
}
Bornie answered 4/7, 2018 at 15:28 Comment(2)
Interesting approach... too bad that parameter can't be readonly. Some mislead person might toggle toggle inside the local function and accidentally kill the second call.Sterculiaceous
I guess that's just a reason to keep the local function small.Sterculiaceous
D
0

A bit late to the party - but this is a different solution I came up with:

for ((bool b, int n) = (false, 0); n < 2; b = true, n++) {
   /* ... */
}

It works in C# 7.3, so it's compatible with .NET Framework.

Darn answered 13/6, 2023 at 11:31 Comment(0)
P
0

Very late but here's the way I did it:

bool High = false;
for (int i = 0; i < 2; i++)
{
//Other code
queues[7].Enqueue(new Values {//....

   High = !High; // Toggle the value of High
}
Pich answered 27/6 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.