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.
Related
I've found out a strange behaviour of Convert.ToString and I would like to understand, why it does behave like this.
Have a look at following code pieces:
string obj = null;
var str = Convert.ToString(obj);
Console.WriteLine(str); // CORRECT: returns null;
all good so far, but:
DBNull obj = DBNull.Value;
var str = Convert.ToString(obj);
Console.WriteLine(str); // ???: returns string.Empty ("")
and
object obj = null;
var str = Convert.ToString(obj);
Console.WriteLine(str); // ???: returns string.Empty ("")
It looks to me like a bug, because when i do a conversion to a string and the input is NULL the result should be default of a string, which is also NULL.
Convert.ToString has a String overload that does nothing:
Returns the specified string instance; no actual conversion is performed.
and its Object overload is defined thus:
The string representation of value, or String.Empty if value is null.
It might be a bit surprising, but there’s no reason to use Convert.ToString on a String expression in the first place.
That's documented behaviour
Convert.ToString Method (Object)
The string representation of value, or String.Empty if value is null.
Convert.ToString Method (String)
value is returned unchanged.
I am trying to convert a text box into a decimal when I try this method it says that inpurt string was not in correct format what is the best way around this.
_record.houseHoldArrearsAmount = Convert.ToDecimal(txtArrearsAmount.Text)
I persume it is because text is "" null and and 0.00 hence it falls over
The compiler run time is causing an exception
The input is blank if the user has not entered a value as of yet
If you know that the text is always going to be a number you can still use Convert but check that the string isn't empty first:
if (!string.IsNullOrWhitespace(txtArrearsAmount.Text))
{
_record.houseHoldArrearsAmount = Convert.ToDecimal(txtArrearsAmount.Text);
}
Obviously this won't update the houseHoldArrearsAmount if it's not a numeric value. What you do in this case depends on your business model. You might want to set it to 0 or you might want to leave it with the old value and report and error.
Alternatively, if the input could be any string, you can use Decimal.TryParse to convert the string to a number.
decimal result;
if (decimal.TryParse(txtArrearsAmount.Text, out result))
{
_record.houseHoldArrearsAmount = result;
}
You can use "TryParse" funtion.
decimal householdArrearsAmount = decimal.Zero;
decimal.TryParse(txtArrearsAmount.Text, out householdArrearsAmount);
_record.householdArrearsAmount = householdArrearsAmount;
You can't use the null coalescing operator (as your suggested in comments), as the string value of the textbox won't be null, it will be an empty string.
You could do the following:
_record.householdArrearsAmount =
(string.IsNullOrWhiteSpace(txtArrearsAmount.Text) ? 0 :
Convert.ToDecimal(txtArrearsAmount.Text));
I was reading this blog post by Eric Lippert http://ericlippert.com/2013/06/17/string-concatenation-behind-the-scenes-part-one/#more-1228 and became aware that the empty string is not an identity of concatenation in C#. I haven't run into a situation that made me aware this was the case and always just assumed it was an identity. I assume there is some good reason why
string NullString = null;
NullString = NullString + String.Empty; // results in and empty string, not null
results in an empty string rather than null, what is that reason? Why is there no identity of string concatenation? Was it made that way for convenience or practicality?
The documentation for String.Concat explains this behavior:
An Empty string is used in place of any null argument.
Basically, the String.Concat method was designed to exhibit this behavior.
Was it made that way for convenience or practicality?
While only the framework design team could directly answer this, this behavior does has some practical benefits. This behavior allows you to concatenate strings with null and not create null results, which reduces the number of explicit null checks required in most code. Without this behavior, someString + "abc" would require null checking, wheras with it, a non-null value is guaranteed.
I must admit that i don't understand "the identity of string concatenation". However, the reason why null + string.Empty is not null but string.Empty is:
because it was implemented in this way.
Have a look:
public static string Concat(string str0, string str1)
{
if (string.IsNullOrEmpty(str0))
{
if (string.IsNullOrEmpty(str1))
{
return string.Empty;
}
return str1;
}
else
{
if (string.IsNullOrEmpty(str1))
{
return str0;
}
int length = str0.Length;
string text = string.FastAllocateString(length + str1.Length);
string.FillStringChecked(text, 0, str0);
string.FillStringChecked(text, length, str1);
return text;
}
}
This is also documented:
The method concatenates str0 and str1; it does not add any delimiters.
An Empty string is used in place of any null argument.
If you ask for the why. I assume because it's safer this way. If you want to concat two strings and one of both is null, why should null be favored instead of string.Empty?
Because it uses a contract, the purpose of which is described at Code Contracts.
From String.Concat:
Contract.Ensures(Contract.Result<string>() != null);
Note that NullString + NullString also returns an empty string.
I recently bumped into an exception in my code because I was trimming a null string.
I replaced it with the following:
SomeValue = (SomeString ?? "").Trim();
Can this code ever fail?
Thanks.
Note: I know I can add a try/catch; I'm just looking to make this line fail-proof without using a try/catch.
This will not fail (ie. throw a NullReferenceException), assuming SomeString is indeed a string.
You could achieve the same in many ways:
SomeValue = (SomeString == null)?string.Empty:SomeString.Trim();
It's not the way I would have done it, but no, this shouldn't ever fail now.
I'd probably write an extension method that calls trim after checking for null. Something like this:
public static string NullTrim(this String str) {
if(str == null) {
return string.Empty;
}
return str.Trim();
}
This allows all of the following to compile and execute without error:
"".NullTrim();
" test ".NullTrim();
((string)null).NullTrim();
Well if it was failing because of NullReferenceException, then now it will definitely not fail because of that. As for the rest, I cannot say without context.
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";
}