null-coalescing operator or conditional operator - c#

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";

Related

Conditional Null Operator invalid type in given context

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".

why var returnText = value as string not working?

I have a Convert method that implements IValueConverter. My first statement is
var returnText = value as string not working to take over the value as string. However, it doesn't work and when I was debugging, I found out the value of the "value" variable didn't assign over to returnText so the returnText is always null. It is odd. Does anybody know why?
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var returnText = value as string;
if (!string.IsNullOrEmpty(returnText))
{
.....
Problem and Solution
The problem is that as string does not convert, it just casts the object to a string. If that doesn't work it will produce null instead. The object must be of string type originally, in this case that is obviously not the case.
One option that would likely work in your case is to call .ToString() on the object like so:
var returnText = value.ToString();
but please note that this really does depend on your object type, and what it's .ToString() method actually produces. You may get a value that you do not expect.
Additional Recommendations
As Tim has commented, ToString() will throw an exception if the object is null to begin with. It is recommended to test for this before calling any method on the object. Something like this will do:
string returnText = null;
if(value != null)
returnText = value.ToString();
Further Reading
See here for more information. A couple of useful quotes from that link:
The as operator is like a cast operation. However, if the conversion isn't possible, as returns null instead of raising an exception.
and
Note that the as operator performs only reference conversions, nullable conversions, and boxing conversions. The as operator can't perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.
try
var returnText = value==null ? "": value.ToString();
Because this var returnText = value as string; means: Try to cast value as string if not, return null.
as (C# Reference) http://msdn.microsoft.com/en-us/library/vstudio/cscsdfbt.aspx
Why System.Convert.ToString() instead of .ToString()......
I'd rather use var returnText = System.Convert.ToString(value); because this will use the IConvertable interface. The ToString() could give a screwed-up result. (like classnames etc)
More info: Convert.ToString Method http://msdn.microsoft.com/en-us/library/astxcyeh.aspx

C# "condition coalescing" operator

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?

?? operator in system.DBNull

Is there an operator or built in function to simplyfy this:
myVal = object1.object2.something(a,b).dataColumn.toString()==""?object1.object2.something(a,b).dataColumn.toString():"-";
I know i can do something like:
string str = object1.object2.something(a,b).dataColumn.toString();
myVal =str==""?"-":str;
but I have many objects and I want to avoid it:
string str1 = object1.object2.something(a,b).dataColumn1.toString();
myVal1==""?str1:"-"
string str2 = object1.object2.something(a,b).dataColumn2.toString();
myVal2==""?str2:"-"
:
string strN = object1.object2.something(a,b).dataColumnN.toString();
myValN==""?strN:"-"
I can also create a function:
private string CheckNull(object dataColumn){
return dataColumn == System.DBNull?"-":dataColumn.toString();
}
myVal1 = CheckNull(object1.object2.something1(a,b).dataColumn.toString())
myVal2 = CheckNull(object1.object2.something2(a,b).dataColumn.toString())
myVal3 = CheckNull(object1.object2.something3(a,b).dataColumn.toString())
The easiest way is to use the ?? operator but the problem is that 'dataColumn' is not compatible with ?? because sometimes returns a system.DBNull instead of a null. Look at the immediate window output:
System.DBNull??"-"
'System.DBNull' is a 'type', which is not valid in the given context
null??"-"
"-"
I wonder if there is some (string) function or operator that can return "-" if dataColumn.toString()=="" without an if..then (because I would have to make many if..then for all of them. Otherwise I rather use the function approach shown above.
string str = object1.object2.something(a,b).dataColumn.toString().if("","-");
How about:
public static class StringHelper {
public static string ValueOrDash(this string value) {
return string.IsNullOrEmpty(value) ? "-" : value;
}
}
Then you can just do:
myVal = object1.object2.something(a,b).DataColumn.ToString().ValueOrDash();
Or better yet:
public static class StringHelper {
public static string ValueOrWhatever(this string value, string defaultValue) {
return string.IsNullOrEmpty(value) ? defaultValue : value;
}
}
myVal = object1.object2.something(a,b).DataColumn.ToString().ValueOrWhatever("-");
If the underlying object is always either a string or DbNull, you could use the as cast operator:
private string CheckNull(object dataColumn){
return dataColumn == (dataColumn as string)??"-":dataColumn;
}
This will also return "-" if the value is an integer for example or some other type.
It's not clear from your code, but if these values are coming from DataRows you could use the new (.NET 3.5) DataRowExtensions.Field function, which will return null instead of DbNull.
You could write an extension method to call on the dataColumn. It wouldn't functionally be much different than your CheckNull method, though.
Or in your first example with str1, str2, strN and such, is there a reason you can't reuse str1 for each? I see you have a method call in your long line of code, you wouldn't want to waste the time running that more often than you need to (especially if it's going to result in the same output every time).

Using null coalescing in foreach statement

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";
}

Categories