1

I have a bit of code, that while simple perhaps isn't immediately obvious as to what it does.

I found @(Model.Count() == 0 ? "no" : Model.Count().ToString()) @(Model.Count() == 1 ? "person" : "people")
@foreach (var item in Model) {
   <div>@item.Name at @item.Email</div>
}

And before I write lots of code like this, I wanted to know if this is a good way of doing this.

Thus the question is, in .NET is there a better framework way of doing this, or is the Ternary method fine

The premise is obviously

  • 0 records = I found no people
  • 1 record = I found 1 person
  • 2+ records = I found 2 people
arulmr
  • 8,620
  • 9
  • 54
  • 69
Dale Fraser
  • 4,623
  • 7
  • 39
  • 76
  • 4
    Depending on what `Model` is, each `Count` and `foreach` might be a new query to the database. You might want to prevent that. Apart from this, I see no problem with the use of `?:` in your code. – dtb Apr 24 '13 at 10:29
  • 7
    `Model.Any()` might be better then `Model.Count() == 0` – I4V Apr 24 '13 at 10:34
  • Both helpful comments, the model is @model IEnumerable – Dale Fraser Apr 24 '13 at 10:36
  • 2
    Technically, it's called the [conditional operator](http://msdn.microsoft.com/en-us/library/ty67wk28.aspx). In theory, C# *could* have other ternary operators. At present it only has one, but it's a bad habit to use the name for a *class* of operators to discuss the single member of that class. – Damien_The_Unbeliever Apr 24 '13 at 10:48

6 Answers6

5

In my opinion it is absolutely fine to use the Ternary conditional operator for this kind of condition.

Developers with experience understand it without thinking about it, but if you want to make it easy readable for beginners, you can also use an if and else construct.

But I would use Any() as @I4V mentioned in the comment.

I found @(Model.Any() ? Model.Count().ToString() : "no") @(Model.Count() == 1 ? "person" : "people")


@foreach (var item in Model) {
   <div>@item.Name at @item.Email</div>
}
Philipp M
  • 1,877
  • 7
  • 27
  • 38
  • I would disagree, experienced developers would recognise the operator but they wouldn't necessarily understand what that piece of code is doing "without thinking about it". Also, it's not exactly the right attitude to have you don't know what sort of level of experience someone who would potentially be maintaining your code will have so you should always write **clear, concise and readable code**. – James Apr 24 '13 at 11:02
  • 2
    You're right, the extension method in your answer is more readable, than this line with two conditional operators. Upvoted your answer. I still think, this it is ok to use. – Philipp M Apr 24 '13 at 11:07
5

If your doing it in a few places, an extension method would solve both your problems (readability & simplified code)

public static string PersonCountString(this IEnumerable<Person> personList)
{
    var count = personList.Count();
    return String.Format("{0} {1}", count > 0 ? count : "no",
                                    count == 1 ? "person" : "people");
}
...
I found (@Model.PersonCountString())
James
  • 80,725
  • 18
  • 167
  • 237
1

To answer your question: no, I find that oneliner not readable, it reads like @(() 0 ? "" : .().()) @(.() == 1 ? "" : "") to me, not to mention the multiple calls to .Count().

You could create a (shared) helper method like this:

string GetCountWithDescription(int count, 
                               string singleItemDescription, 
                               string multipleItemsDescription)
{
    switch (count)
    {
        case 0:
            return "no " + multipleItemsDescription;
        case 1:
            return "1 " + singleItemDescription;
        default:            
            return count + " " + multipleItemsDescription;
    }
}

Reusable too, so you can stick it in a separate file so it won't clutter your code, and you can simply call it in from every view like this:

@GetCountWithDescription(Model.Count(), "person", "people")
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

What do you try to achieve? Better readability or faster code (development)? If the aim is for better readability, then I suggest to keep the ternary operation inside strings, for example:

string modelCountStr = Model.Count() == 0 ? "no" : Model.Count().ToString(); string modelPluralStr = Model.Count() == 1 ? "person" : "people";

Fendy
  • 4,565
  • 1
  • 20
  • 25
0

Considering you will have to use Count() if any users are present:

@{ 
    var count = Model.Count();
}

I found @(count == 0 ? "no" : count) @(count == 1 ? " person" : " people")
Vimal Stan
  • 2,007
  • 1
  • 12
  • 14
0

Another way to make it more readable would be to opt for a solution where there are as few or ideally zero conditionals involved, if possible.

This is my take:

@{ 
    var count = Model.Count(); 
}
I found @string.Format(new[] { "no people", "{0} person", "{0} people"} [Math.Min(count, 2)], count)

Arguably Math.Min is responsible for some kind of branching, but I think this is much easier to understand.

Oskar Sjöberg
  • 2,728
  • 27
  • 31