Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String concatenation with ternary operator

Tags:

c#

asp.net-mvc

I am creating a SelectList of various contacts. I want the text shown to be a combination of FirstName, MiddleInit(if possible), and LastName.

IEnumerable<SelectListItem> items = contacts
.Select(r => new SelectListItem()
{
    Value = r.ContactID.ToString(),
    Text = r.FirstName + " " 
    + string.IsNullOrEmpty(r.MiddleInit) ? r.MiddleInit + ". " : ""
    + r.LastName
});

I am getting the error:

Error   4   Cannot implicitly convert type 'string' to 'bool'   C:\Users\cu551d\Documents\Visual Studio 2010\Projects\WVM\WVM\Controllers\SOWController.cs  181 15  WVM

I'm guessing it has something to do with my syntax. Am I able to do something like this in c#?

Also, should I include a Trim() statement on MiddleInit? I thought this error was very strange as IsNullOrEmpty does in fact return a bool. I also tried (string.IsNullOrEmpty(r.MiddleInit) == true ) ..

like image 879
Jeff Avatar asked Dec 04 '12 22:12

Jeff


3 Answers

The problem is due to operator precedence causing the compiler to parse the expression in a way that you're not expecting. Just wrapping the ternary expression in parens will politely explain to the compiler what it is you mean to say.

As a side note, looking at the logic of the expression, I think the order of the result terms is incorrect. I've switched them in the code below.

IEnumerable<SelectListItem> items = contacts
.Select(r => new SelectListItem()
{
    Value = r.ContactID.ToString(),
    Text = r.FirstName + " " 
    + (string.IsNullOrEmpty(r.MiddleInit) ? "" : r.MiddleInit + ". ")
    + r.LastName
});

More explanation

Without (, + has a higher precedence than ?:, so the expression in your question is being parsed as if it said:

Test = (r.FirstName + " " + string.IsNullOrEmpty(r.MiddleInit)) ? (r.MiddleInit + ". ") : ("" + r.LastName)

So the source of your error is that the conditiional part of the ?: operator is actually a string - which will contain something like "Andrew true". Also note that r.LastName gets combine with the third term of the ?: operator.

The Trim() question

If there's a chance that r.MiddleInit could contain whitespace, then using Trim() would help, but it would be better to change the test to String.IsNullOrWhiteSpace(r.MiddleInit).

like image 142
Andrew Cooper Avatar answered Sep 18 '22 17:09

Andrew Cooper


Try grouping in parenthesis. It also looks like you're doing the conditional operator backwards:

IEnumerable<SelectListItem> items = contacts
.Select(r => new SelectListItem()
{
    Value = r.ContactID.ToString(),
    Text = r.FirstName + " " +
        (string.IsNullOrEmpty(r.MiddleInit) ? "" : (r.MiddleInit + ". ")) +
        r.LastName
});

Another Technique

Since you are converting it to empty string anyway, you might consider this too:

Text = r.FirstName + " " + (r.MiddleInit ?? "") + r.LastName

The ?? is called the Null Coalescing Operator. It will return whatever is on the left if that value is not null, otherwise whatever is on the right.

http://msdn.microsoft.com/en-us/library/ms173224.aspx

EDIT: while cleaner, this won't quite work for your case since you need the period after the initial. But be aware it does exist!

like image 31
akatakritos Avatar answered Sep 17 '22 17:09

akatakritos


Try wrapping your arguments in your ternary

IEnumerable<SelectListItem> items = contacts
.Select(r => new SelectListItem()
{
    Value = r.ContactID.ToString(),
    Text = r.FirstName + " " 
    + (string.IsNullOrEmpty(r.MiddleInit) ? (r.MiddleInit + ". ") : ("" + r.LastName))
});
like image 43
sa_ddam213 Avatar answered Sep 19 '22 17:09

sa_ddam213