Using Elvis operator in combination with string.Equals - c#

I wonder why the following code works in C# 6.0:
(In this example data is a random class containing val as a public string)
if ("x".Equals(data.val?.ToLower()) { }
But the following line isn't:
if (data.val?.ToLower().Equals("x")) { }
Visual Studio shows me the following error:
Cannot implicitly convert type 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?)

if ("x".Equals(data.val?.ToLower()) { }
Will eventually return a boolean because the of Equals call but this:
if (data.val?.ToLower().Equals("x")) { }
when the expression is evaluated it will return a System.Nullable<bool> which is different than a bool (former is a struct that can be assigned the value null while the latter can only be true or false) the the if expects. Also, in C# a null value doesn't evaluate to false (according to the C# specification).

I don't have c# 6.0 to test but this should work
if (data.val?.ToLower().Equals("x") ?? false) { }

The first statement is evaluating the return value of Equals whereas the second statement evaluates to bool? which could be null.

Further to the other answers I think it's useful if you write the equivalent code out long hand so you can see what's going on.
The first line is equivalent to:
string temp = data.val != null ? data.val.ToLower() : null;
if ("x".Equals(temp)) { }
which is perfectly valid and obvious.
The second statement is equivalent to:
bool? temp = data.val != null ? data.val.ToLower().Equals("x") : null;
if (temp) { } //error
This is perhaps less obvious but the statement data.val?.ToLower().Equals("x") will return null if data.val is null otherwise it will return the result of data.val.ToLower().Equals("x"). Because the statement can return null or bool the type of the entire statement is bool? but you can't use a bool? in an if directly.
As others have pointed out, converting the bool? to a bool will fix your issue. One way of doing that is to use GetValueOrDefault():
if (data.val?.ToLower().Equals("x").GetValueOrDefault()) { }

Related

Returning result of statement including the safe navigation operator as boolean

I just started using the safe navigation operator in C# for the first time and I am wondering wether this is a correct use case for that operator:
public bool HasAttributes
{
get
{
return this.SomeClassMember?.Attributes?.Count > 0;
}
}
Why exactly does this code not give me a compiler error? I thought that the result would be null if for example this.Notification or this.Notification.Attributes would be null, but return null on the other hand does not work as it does not seem to implicitly convert to false. If I am not using the operator correctly here, could someone explain how I use it correctly in my use case?

How to null coalesce for Boolean condition?

I'm trying to safely check if an IList<> is not empty.
var Foo = Bar.GimmeIListT(); // Returns an IList<SomeObject>
if (Foo?.Any())
// Do cool stuff with items in Foo
But there is an error with the condition:
Cannot implicitly convert 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?)
So it seems the condition evaluates to a nullable bool, so I try
if (Foo?.Any().Value())
But this is no good either:
'bool' does not contain a definition for 'Value' and no extension .... blah blah blah
So in the first instance it complains that it is a nullable bool but in the second it complains that it isn't.
As another avenue I try:
if (Foo?.Any() == true)
This works - but it shouldn't because this uses an implicit conversion which the first message said it didn't want!
What is going on? What is the correct way to do this?
You can compare with the bool? if you use ==, that's indeed the best/simplest approach:
if (Foo?.Any() == true) ...
as to the why it's not allowed in an if but with ==, Jon Skeet can explain it much better:
There's no implicit conversion from Nullable<bool> to bool. There is
an implicit conversion from bool to Nullable<bool> and that's what
happens (in language terms) to each of the bool constants in the first
version. The bool operator==(Nullable<bool>, Nullable<bool>) operator
is then applied. (This isn't quite the same as other lifted operators - the result is just bool, not Nullable<bool>).
In other words, the expression fred == false is of type bool,
whereas the expression fred is of type Nullable<bool> hence you
can't use it as the "if" expression.
So the if allows only bool and you have a bool?, but the == operator converts the bool to a bool? and you can compare two bool?.
Edit:
It seems like the cause of the bool? is the Foo?.Any() itself. If you do not want to compare it with true, I would suggest you to have temporary variable:
bool? any = Foo?.Any();
if (any.Value) ...
Alternatively, if the object is a class, you could use FirstOrDefault() != null as checking condition. It won't take time because it will only get the first object:
if (Foot?.FirstOrDefault() != null)...
I will go with the temporary variable or the Foo?.Any() == true option though.
Original:
Note: It is to my surprise too that if (a?.Any()) cannot be followed by .Value() or .Value(!).
I think what you need is Value (property) without () (method):
if (Foo?.Any()?.Value) ...
bool? has .Value (property) which is a bool.
Any() returns bool but Foo?.Any() will return bool?
So Foo?.Any().Value won't compile since Any() returns a bool that doesn't have a member Value.
If Foo is null, Any() won't be executed because the statement will return null without interpreting the part behind the ?. operator.
But if you put Foo?.Any() in paranthesis, you are able to work with the result of type bool? and check it via Value or GetValueOrDefault():
(Foo?.Any()).GetValueOrDefault()
more syntactic sugar, the null-coalescing operator. C# 8.0 or later
if (Foo?.Any() ?? false) { }

Odd C# Ternary Operator Behavior

So I came across some very baffling behavior of the native ternary operator in C# today. The ternary operator is sending the wrong data type to the method I'm calling. The basic premise is I want to convert the decimal value to an int if decimalEntry == false so it will get stored in a database as an int Here is the code:
decimal? _repGroupResult = 85.00
int? intValue = null;
bool decimalEntry = false;
if (decimalEntry == false)
{
intValue = (int?) _repGroupResult;
}
Console.WriteLine("Sending to ResultAdd via ternary operator");
RepGBParent.ResultAdd(this.RepInfo.ResultID, decimalEntry ? _repGroupResult : intValue);
Console.WriteLine("Sending to ResultAdd via if statement");
// All other tests - just add the rep group result
if (decimalEntry)
{
RepGBParent.ResultAdd(this.RepInfo.ResultID, _repGroupResult);
}
else
{
RepGBParent.ResultAdd(this.RepInfo.ResultID, intValue);
}
The method I'm calling ResultAdd is here:
public void ResultAdd(int pResultID, object pResultValue)
{
if (pResultValue == null) { return; }
Console.WriteLine(this.TestInfo.TestNum + ": " + pResultValue.GetType());
....
}
The ternary operator receives a decimal while the if statement sends an int. As shown by the output code below:
I consider myself a programmer of reasonable talent and this really threw me back today. I played around with it for 2-3 hours and figured out the best way to post it here so I'm clear of the issue I'm having.
Please avoid "why are you even doing it that way" type responses. I simply want to know why there is a difference here between the ternary operator and the if statement.
The only other post that I found that was closely related was this one but it didn't quite match up:
Bizarre ternary operator behavior in debugger on x64 platform
The ternary operator is - well - an operator which is only a special kind of method. And as any other method, it can only have one single return type.
What you try to do is to use the operator to return a decimal? or an int? depending on a condition. That is not possible.
What happens is that the compiler knows that there is an implicit conversion from int? to decimal?, but not the other way round. So it infers the return type of the operator as decimal? and implicitly converts your intValue into a decimal?.
The ternary expression returns a single type, not a type conditional on the result of the evaluation.
Your int is promoted to decimal in order to fullful that requirement.
If the conversion could not be applied, you would get a complier error.
Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
https://msdn.microsoft.com/en-us/library/ty67wk28.aspx

C# Null propagating operator / Conditional access expression & if blocks

The Null propagating operator / Conditional access expression coming in c#-6.0 looks like quite a handy feature. But I'm curious if it will help solve the problem of checking if a child member is not null and then calling a Boolean method on said child member inside an if block:
public class Container<int>{
IEnumerable<int> Objects {get;set;}
}
public Container BuildContainer()
{
var c = new Container();
if (/* Some Random Condition */)
c.Objects = new List<int>{1,2,4};
}
public void Test()
{
var c = BuildContainer();
//Old way
if ( null != c && null != c.Objects && c.Objects.Any())
Console.Write("Container has items!");
//C# 6 way?
if (c?.Object?.Any())
Console.Write("Container has items!");
}
Will c?.Object?.Any() compile? If the propagating operator short circuits (I assume that's the right term) to null then you have if (null), which isn't valid.
Will the C# team address this concern or am I missing the intended use case for the null propagating operator?
It won't work this way. You can just skip the explanation and see the code below :)
As you know ?. operator will return null if a child member is null. But what happens if we try to get a non-nullable member, like the Any() method, that returns bool? The answer is that the compiler will "wrap" a return value in Nullable<>. For example, Object?.Any() will give us bool? (which is Nullable<bool>), not bool.
The only thing that doesn't let us use this expression in the if statement is that it can't be implicitly casted to bool. But you can do comparison explicitly, I prefer comparing to true like this:
if (c?.Object?.Any() == true)
Console.Write("Container has items!");
Thanks to #DaveSexton there's another way:
if (c?.Object?.Any() ?? false)
Console.Write("Container has items!");
But as for me, comparison to true seems more natural :)
Null-conditional operator would return null or the value at the end of expression. For value types It will return result in Nullable<T>, so in your case it would be Nullabe<bool>. If we look at the example in the document for Upcoming Features in C# (specified here), it has an example:
int? first = customers?[0].Orders.Count();
In the above example, instead of int, Nullable<int> would be returned. For bool it will return Nullable<bool>.
If you try the following code in Visual Studio "14" CTP:
Nullable<bool> ifExist = c?.Objects?.Any();
The result of the above line would be a Nullable<bool>/bool?. Later you can do the comparison like:
Using null-coalescing operator ??
if (c?.Object?.Any() ?? false)
Using Nullable<T>.GetValueOrDefault Method
if ((c?.Objects?.Any()).GetValueOrDefault())
Using comparison against true
if (c?.Objects?.Any() == true)
var x = c?.Objects?.Any() is going to give you a nullable boolean, and as others have said, this means you can use an equality operator like this
x == true
or you can use null coalescing like this to have your result not be nullable
var x = c?.Objects?.Any() ?? false
But, personally, I think that 3-state (nullable) booleans are code smell. Even if this one is practically invisible, its existence should encourage you to think about what you are actually trying to do and determine if a nullable boolean is actually the way to go. In this case, I think that what you really want to do is something like this -
var objects = c?.Objects ?? Enumerable.Empty<Object>();
if (objects.Any())
{
...
}
Put that in an extension method and it will be even more succinct -
public static bool IsNullOrEmpty<T>(this IEnumerable<T> collection)
{
return !(collection ?? Enumerable.Empty<T>()).Any()
}

Rewrite HasValue to the ?? Operators

Is it safe to rewrite the following code:
bool b = foo.bar.HasValue ? foo.bar.Value : false;
to
bool b = foo.bar.Value ?? false;
where bar is the nullable type bool?
The easiest fix there is
bool b = foo.bar.GetValueOrDefault();
which is also actually cheaper than .Value as it omits the has-value check. It will default to default(T) , which is indeed false here (it just returns the value of the underlying T field, without any checks at all).
If you need a different default to default(T), then:
var value = yourNullable.GetValueOrDefault(yourPreferredValue);
What you want is:
bool b = foo.bar ?? false;
This is (surprisingly) safe and an intended use for the null-coalescing operator.
The ?? operator is called the null-coalescing operator and is used to define a default value for a nullable value types as well as reference types. It returns the left-hand operand if it is not null; otherwise it returns the right operand.
Source: http://msdn.microsoft.com/en-us/library/ms173224.aspx
In the case of Nullable<T>, it is functionally equivalent to Nullable<T>.GetValueOrDefault(T defaultValue).
The code:
bool b = foo.bar.Value ?? false;
Will cause a compiler-error, because you cannot apply the operator to value types, and Nullable<T>.Value always returns a value-type (or throws an exception when there is no value).
No - this is not safe.
The line:
bool b = foo.bar.Value ?? false;
will throw an InvalidOperationException if foo.bar has no value.
Instead use
var b = foo.bar ?? false;
Update - I just learned about .GetValueOrDefault(); from the other answers - that looks like a very good suggestion to use!
Update 2 - #ProgrammingHero's answer is also correct (+1 added!) - the line:
bool b = foo.bar.Value ?? false
actually won't compile - because of Error 50 Operator '??' cannot be applied to operands of type 'bool' and 'bool'
Nope.
The Value property returns a value if
one is assigned, otherwise a
System.InvalidOperationException is
thrown.
From: http://msdn.microsoft.com/en-us/library/1t3y8s4s%28v=vs.80%29.aspx
So if hasValue is false then you will get an exception thrown in your second one when you try to run it.
ffoo.bar ?? false would be more safer to use
bar.Value ?? false
has compilation error, because left operand of ?? operator should be of reference or nullable type.
Maybe you have a look at this article in Stackoverflow too - it is an elegant null checking in the style obj.IfNotNull(lambdaExpression) - returning the object you want if obj is not null otherwise just null (but without throwing an exception).
I used it with the Entity Framework if you're accessing a referenced entity, e.g.
var str=Entity1.Entity2.IfNotNull(x=>x.EntityDescription) ?? string.Empty
which returns EntityDescription contained in Entity2 which is referenced by Entity1 - or an empty string if any object Entity1 or Entity2 is null. Without IfNotNull you would get a long and ugly expression.
The extension method IfNotNull is defined there as follows:
public static TOut IfNotNull<TIn, TOut>(this TIn v, Func<TIn, TOut> f)
where TIn : class
where TOut: class
{
if (v == null) return null; else return f(v);
}
Update:
If you update the code to C# version 6.0 (.NET Framework 4.6 - but seems to support older frameworks 4.x too), there is a new operator available which makes this task easy: The "elvis" operator ?..
It works as follows:
var str=(Entity1.Entity2?.EntityDescription) ?? string.Empty
In this case, if Entity2 is null, evaluation stops and (...) becomes null - after which the ?? string.empty part replaces null by string.Empty. In other words, it works the same way as .IfNotNull(...) would.
foo.bar.Value represents the non-nullable value when there is one, and throws an InvalidOperationException if there’s no real value.

Categories

Resources