0

In my model I'm receiving a property that's an integer composed of bit flags denoting access to a set of facilities. So, if the objects has A, B, D but lacks C, the code for it would be 7 (1 + 2 + 0 + 4).

In the table I'm generating, I prefer to present it as a bunch of columns with "Y" if the corresponding facility's present in each individual object's information.

But when typed a pattern emerged, as follows.

<td>
  @if ((station.Facility & 1) == 1) {<span>yes</span>}
</td>
<td>
  @if ((station.Facility & 2) == 2) {<span>yes</span>}
</td>
...
<td>
  @if ((station.Facility & 1024) == 1024) {<span>yes</span>}
</td>

Any half-lousy excuse to a code monkey feels that there should be much fewer lines here because we should repeat

<td>
  @if ((station.Facility & bit) == bit) {<span>yes</span>}
</td>

except for the tiny bit that's pooping through the powers of 2. Me being a bit DUI (developing under influence) because of the 2016 just starting, might be the reason why I can't see how to do that.

Nevertheless - how do I do that?


Also, I also have a suspicion that the conditional expression may be simplified, as there are nested parenthesis present right now. I was surprised that AND (& operator) bound weaker than equality (== operator) but that's how I solved it. I've considered using shifting (<< operator) but the syntax got actually more complex and given that the speed isn't exactly an issue, I don't have to use it (unless it's simplifying the code).

Is there a smoother way to achieve that?

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • 1
  • @AlexeiLevenkov I probably should. Just a quick follow-up: your suggestions regards a better syntax for the conditional expression, not how to put all the TDs in a single loop, right? – Konrad Viltersten Jan 01 '16 at 01:27
  • 1
    Since first 2 bits are different you'd probably not get any better code of combining all... 4-1024 can be coded like `for (var bit=4; bit <=1024; bit = bit * 2) { @if( (s.F & bit)== bit) { ....` – Alexei Levenkov Jan 01 '16 at 01:47
  • If you are using masking and that's what you mean by numerical flags, I think it'd be wiser to make use of left shift and right shift operators (`>> <<`) instead of the `&`. Although I'm not sure what you are actually doing but in case of masking then using those you can do combinations as well. For example if access is both `3` and `2` like ReadOnly and WriteToTableX that can be helpful. – Transcendent Jan 01 '16 at 02:36
  • 1
    Have you considered creating an `enum` with the [flags attribute](https://msdn.microsoft.com/en-us/library/system.flagsattribute%28v=vs.110%29.aspx) so that you can name the bits? When you mask a bit off you really only care that the result is non-zero, hence you don't need to repeat the mask bit in the test. – HABO Jan 01 '16 at 02:59
  • Just curious, but why wouldn't you perform these calculations in your controller? – Lawrence Johnson Jan 01 '16 at 03:01
  • The formatting side of things could be tidied up with one or more custom HTML helpers. Pass in a value and a `enum` type and it can do the fiddling for you. The [description attribute](https://msdn.microsoft.com/en-us/library/system.componentmodel.descriptionattribute%28v=vs.110%29.aspx) can be used on the enum values to provide display strings. Create different helpers for creating a list of values, list of yes/no per bit, a series of table data elements, ... . You could also provide template(s), e.g. `"%s"`, to the helpers. – HABO Jan 01 '16 at 04:25
  • @LawrenceJohnson Interesting point. I'm going to present my reason and I'd be happy to get some CC on it. In the controller, I filter and serve the objects (*Where*'ing, not *Select*'ing). If I transform the objects to what's being shown in the view, I'll need to declare a new class (*Station* will become *StationGui* or something). My aim was to use the same class from "the bones" up to the viewer for simplicity. Also, I prefer using hard types and not abstract one because my experience is that there will be dragons when I do. You take/recommendation is warmly appreciated. – Konrad Viltersten Jan 01 '16 at 13:35
  • @HABO Perhaps I made a mental booboo. Since the DB contains just an integer, hence making EF autogenerate a property of type *int*, I intuitively bounce **that** around. At the moment it's not decided yet if that value will be split into a column each or if we'll just generate a bunch of icons in a single column. That's why I'm prone to keeping the final transformation as close to the GUI as possible.But using enumeration will **definitely** improve readability, so I'll put them in. Good suggestion! – Konrad Viltersten Jan 01 '16 at 13:43
  • @AlexeiLevenkov I've looked again at the shifting instead of masking. However, the syntax I get is in fact longer and less readable, at least to me. Speed is of no concern, luckily. But the code needs to be as smooth as possible (private project on free time, so I get to joggle a bit without cost, hehe). – Konrad Viltersten Jan 01 '16 at 14:26
  • 1
    @Transcendent I realized that I wasn't clear on what's being asked, so I shortened down the question to the most relevant parts (main one being using *for* in Razor, which I for some alcoholic reason didn't get to work last night). – Konrad Viltersten Jan 01 '16 at 14:28
  • 1
    @KonradViltersten In my experience, anything you can do to prepare the ViewBag/ViewModel for rendering in the view is best done in the controller. Many other people in your post have looked at your problem much closer than I have, so I may be speaking out of turn. I just quickly noticed the TDs with if values, and figured it might be easier to set the values for each item in the controller so that your razr/view is simply rendering the "yes" if its there for each column. Either way, glad you found a solution. – Lawrence Johnson Jan 01 '16 at 16:37

1 Answers1

1

Try for statement.

@{ int max = 10; }

@for(int i = 1; i <= max; i++)
{
  if (station.Facility & (1 << i-1) != 0)
  {<span>yes</span>}
}

Also to be read - a post here.

Community
  • 1
  • 1
monkeyhouse
  • 2,875
  • 3
  • 27
  • 42
  • This was spot-on. I found a typo in the code you pasted but the message was there, so +1, definitely. I also took the liberty to shorten it to be more to-the-point. Hope you don't mind. – Konrad Viltersten Jan 01 '16 at 13:51