Trying to figure out how to get the null coalescing operator to work in a foreach loop.
I'm checking to see what a string ends with and based on that, route it to a certain method. Basically what I want to say is....
foreach (String s in strList)
{
if s.EndsWith("d") ?? Method1(s) ?? Method2(s) ?? "Unknown file type";
}
In attempting to do this, of course you get the "Operator ?? cannot be used on type bool and type string." I know there is other ways to do it, just want to see how it can be done with null coalescing.
Have a good weekend.
#Richard Ev: Oh yes of course. Switch, if else, etc. Was just curious how it
could be handled
#Jon Skeet: After reading your comments it hit me, this is just bad! I am
interested in two file extensions basically. If a file ends with "abc" for
instance, send to method 1, if the file ends with "xyz" send to method 2. But
what if a file ends with an extension of "hij"...boom, you're done.
Thanks to Brian and GenericTypeTea as well for the thoughful input
I'm content calling it closed.
It looks like you want to use the normal ternary operator, not null coalescing. Something like:
(s.EndsWith("d") ? Method1(s) : Method2(s)) ?? "Unknown file type";
This is equivalent to:
string result;
if (s.EndsWith("d"))
result = Method1(s);
else
result = Method2(s);
if (result == null)
result = "Unknown file type";
return result;
I think you want a combination of the conditional (ternary) operator and the null coalescing operator:
foreach (String s in strList)
{
string result = (s.EndsWith("d") ? Method1(s) : Method2(s))
?? "Unknown file type";
}
In simple english, this will do the following:
If s ends with d, then it will try Method1.
If s does not end with d then it will try Method2.
Then if the outcome is null, it will use "Unknown file type"
If the outcome is not null, it will use the result of either A or B
I think the compiler gave you the appropriate answer, you can't.
Null coalescing is essentially this if statement:
if(x == null)
DoY();
else
DoZ();
A boolean value cannot be null, so you can't coalesce it like that. I'm not sure what your other methods return, but it seems like you want a simple || operator here.
You should first use the ?? null coalescing operator to guard against a null s reference. Then use the ? ternary operator to choose between Method1 and Method2. Finally use the ?? null coalescing operator again to provide the default value.
foreach (string s in strList)
{
string computed = s;
computed = computed ?? String.Empty;
computed = computed.EndsWith("d") ? Method1(s) : Method2(s);
computed = computed ?? "Unknown file type";
}
Related
Working with a Legacy Application, ASP.Net, c#.
Trying to append my log4net messages with the SessionWrapper.UserDisplayName
The hiccup is if the sessionwrapper is not defined, i don't want it to bomb, i just want it to treat it as null or empty and I'm trying to avoid writing a multiple lines of code.
Using this as the base for my idea:
banana = null;
string result2 = banana?.prop1 + "something new";
result 2 = something new
Applying that concept to my code:
SessionWrapper?.UserDisplayName + "error message"
I get an error compiling saying:
"SessionWrapper is a type and invalid int the current context"
Any insight is greatly appreciated -
A type is not a value and is therefore never null. If UserDisplayName is a static property of this type, then it might be null; however, it is okay to concatenate null with a string. null will be treated like an empty string.
Simply write
string result = SessionWrapper.UserDisplayName + "error message";
In banana?.prop1 the null-condition-operator is only useful if banana is null. The expression is equivalent to banana == null ? (string)null : banana.prop1.
If you want to treat the case where prop1 could be null, then use the null-coalescing operator ??.
string result2 = (banana.prop1 ?? "<empty>") + "something new";
Of course you can combine the two.
string result2 = (banana?.prop1 ?? "<empty>") + "something new";
Now, both, banana and prop1 can be null. In both cases you will get the result "<empty>something new".
I have this weird error.
On this code, as you can, I have a query on database, return it as DataTable and explicitly declared it null. Now I have a condition to check this if this is null and pass it to a string variable. Everything works fine. I receive an empty string. No exception found.
DataTable dtDateUploaded = _BL.GetRecordByDataTableResults();
dtDateUploaded = null;
string strUploadedDate = dtDateUploaded == null ? string.Empty :
dtDateUploaded.Rows[0].IsNull(0) ? string.Empty :
dtDateUploaded.Rows[0][0].ToString();
But when I used the same condition and pass it directly to a Label control for example (and not use a string variable), I get an object reference error. I wonder why do I get an object reference error if I just used the same code on my string variable above?
LblRecordCount.Text = "Record Uploaded last: " + dtDateUploaded == null ? string.Empty :
dtDateUploaded.Rows[0].IsNull(0) ? string.Empty :
dtDateUploaded.Rows[0][0].ToString();
And the weird part is that this works:
LblRecordCount.Text = "Record Uploaded last: " + strUploadedDate;
You get this error because, in the second example, the + operator has precedence over the == operator so you are trying to concatenate the "Record Uploaded last" string to a null variable.
Instead, in the first example, the = operator has lower precedence than the == operator and no error occurs because the ternary operators are evaluated before the assignment.
You should use brackets to group the ternary operators logic together
LblRecordCount.Text = "Record Uploaded last: " + (dtDateUploaded == null ? string.Empty :
dtDateUploaded.Rows[0].IsNull(0) ? string.Empty :
dtDateUploaded.Rows[0][0].ToString());
See MSDN on C# Operators
In C# 6.0, string interpolations are added.
string myString = $"Value is {someValue}";
How are null values handled in the above example? (if someValue is null)
EDIT:
Just to clarify, I have tested and am aware that it didn't fail, the question was opened to identify whether there are any cases to be aware of, where I'd have to check for nulls before using string interpolation.
That's just the same as string.Format("Value is {0}", someValue) which will check for a null reference and replace it with an empty string. It will however throw an exception if you actually pass null like this string.Format("Value is {0}", null). However in the case of $"Value is {null}" that null is set to an argument first and will not throw.
From TryRoslyn, it's decompiled as;
string arg = null;
string.Format("Value is {0}", arg);
and String.Format will use empty string for null values. In The Format method in brief section;
If the value of the argument is null, the format item is replaced with
String.Empty.
It seems that the behavior depends on which underlying formatting methods are called, and the implementation of these can change over time. If you get a null formated into the string such as "(null)", it is not sure this will stay the same over several years. In some newer version of .NET it can start throwing an exception.
So I think the most safe approach is to make some condition to avoid using the null. Write a simple ternary operation like:
int? someValue = 5;
var valueStr = (someValue is not null) ? someValue.ToString() : string.Empty;
var myString = $"Value is {valueStr}";
It is an extra line of code, but at least the behavior is controlled.
Is there any special expression or some kind or syntactic sugar built in in C# that would allow one to change a variable's value or leave it alone depending on condition?
I mean something that would do following:
str = (condition) ? "modifiedString" : str;
or
if (condition) str = "modifiedString";
But with simplicity of null coalescing operator. Something like
str = (condition) ?? "modifiedString"
How about
if(condition)
str = "modified"
Isn't that exactly what you want?
Which coding style do you prefer:
object o = new object();
//string s1 = o ?? "Tom"; // Cannot implicitly convert type 'object' to 'string' CS0266
string s3 = Convert.ToString(o ?? "Tom");
string s2 = (o != null) ? o.ToString() : "Tom";
s2 or s3?
Is it possible to make it shorter? s1 does not obviously work.
In this case, I think my preference would be:
string s1 = (string)o ?? "Tom";
Or:
string s1 = (o as string) ?? "Tom";
Depending on whether or not o is really expected to be a string or not. Either way, I prefer these because they better express what's being done, and don't pass this through an unnecessary conversion if o is already a string.
As a general rule, I prefer whichever is clearer and/or actually works. When working with strings, I often need to write something like this instead:
string result = !string.IsNullOrEmpty(value) ? value : "Default";
...which can't really be done at all with the null-coalescing operator. On the other hand, if I'm trying to coalesce a large number of values, it's about 500 times better:
var result = firstTry ?? secondTry ?? thirdTry ?? fourthTry ?? fifthTry;
Try writing that with the ternary operator instead.
If the difference is not this dramatic, if it's just going to be a couple of characters on one line of code, it really doesn't matter, just use whatever you're comfortable with.
This will also work, though calling ToString on a string feels a bit strange:
string s4 = (o ?? "Tom").ToString();
For this case I'd prefer using the ternary operator since it expresses the intent more clearly and avoids a redundant call to Convert.ToString(). In general I would prefer the null coalescing operator if the conversion is to an object of the same type e.g.
string s1 = null;
string s2 = s1 ?? string.Empty;
IMO, I tend to use:
var s = obj ?? "tom";
when s is the same type as obj without using the Convert or any other type of casting.
Then, I use:
var s = obj != null
? obj.ToString()
: "tom";
when I need to cast or have some other kind of transformation on the right side before assigning to the left side...
Just my style of coding, I suppose.
I don't like either. Converting object to a specific type is fraught with trouble, it should never be hidden in an expression. I'd much prefer that, if it bombs, then it does so on a specific statement. And to make it absolutely obvious to a reader of the code that this conversion is being done. So, at the very minimum:
string s1 = o as string;
string s2 = s1 ?? "Tom";