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.
Related
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) { }
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()
}
I was just wondering why the following code doesn't work (please keep in mind that I set age to be nullable):
myEmployee.age = conditionMet ? someNumber : null;
Yet the following works fine:
if(conditionMet)
{
myEmployee.age = someNumber;
}
else
{
myEmployee.age = null;
}
Why can't I set the value to null in a conditional operator?? All these if statements in my code is not nice.
Thanks.
The types on both sides have to be the same (or be implicitly convertible):
myEmployee.age = conditionMet ? someNumber : (int?)null;
From the docs:
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.
You can, just be clear about the type that null should be interpreted as:
myEmployee.age = conditionMet ? someNumber : (int?)null;
Look at what the documentation has to say:
[MSDN] The default value for a nullable type variable sets HasValue to false. The Value is undefined.
The default is thus null. Which means that you can simply do:
if (conditionMet)
myEmployee.age = someNumber;
There is no need for more obscure code syntax.
If required you can initialize it with null in advance, if it somehow was not the default, like so:
myEmployee.age = null;
if (conditionMet)
myEmployee.age = someNumber;
The types of the parts of the ternary statement must be implicitly castable to a common base. In the case of int and null, they aren't. You can solve this by making age a Nullable<int> (or int?) and casting someNumber to int?.
EDIT to clarify: you can set the value to null with a ternary statement with proper casting. The problem here isn't that you're trying to set a value to null with a ternary statement. It's that the compiler-inferred return types of the two expressions involved in the ternary statement cannot be implicitly casted to a common base type.
as string caused me a problem when dealing with object arrays. The values after execution are shown in the comments. Should it work this way?
object[] array = new object[2];
array[0] = 0.33;
array[1] = "0.33";
string a = array[0] as string; // a == null !!!??????
string b = array[1] as string; // b == "0.33"
string a2 = array[0] == null ? "" : array[0].ToString(); // a2 == "0.33"
string a3 = Convert.ToString(array[0]); // a3 == "0.33"
Yes, it should.
as is a cast operator.
It can only be used to cast an object to a type that it actually is (or a superclass thereof).
x as Y returns null if x isn't a Y.
the as-operator returns null when it fails to cast an object to the specified type. in this case it failed to cast 0.33 to type string, so string a is null.
MSDN:
The as operator is like a cast operation. However, if the conversion
is not possible, as returns null instead of raising an exception
So yes, the behaviour you are observing is correct.
The as operator is a casting operation, not a conversion operation, so it will only produce the value is the same type, or a super- or sub-class or the type you are trying to cast to.
(Unlike a regular cast, the as operator also does not perform user-defined conversions using the operator keyword.)
"as string" is not a synonym for "ToString()". You are using the "as" operator, and happened to pass it string as a type.
Definition of the as operator:
Remarks
The as operator is like a cast except that it yields null on conversion failure instead of raising an exception. More formally, an expression of the form:
expression as type
is equivalent to:
expression is type ? (type)expression : (type)null
The 'as' operator is basically like casting into a System.Type however the only difference is that it returns a null value if the cast fails instead of throwing an exception.
Check out this link for more info
http://msdn.microsoft.com/en-us/library/cscsdfbt(v=vs.71).aspx
array[0] is a double and cannot be casted to string, hence null.
Call ToString(), most types override it to return something meaningful.
int? x = null;
x = x + 1; // Works, but x remains null
I would expect the compiler to attempt to cast x as an int, but apparently it does not.
Edit by 280Z28: Changed NullReferenceException to InvalidOperationException, which is what Nullable<T>.Value throws when HasValue is false.
This is per the specification for lifted binary operators. From §7.2.7:
For the binary operators
+ - * / % & | ^ << >>
a lifted form of an operator exists if the operand and result types are all non-nullable value types. The lifted form is constructed by adding a single ? modifier to each operand and result type. The lifted operator produces a null value if one or both operands are null (an exception being the & and | operators of the bool? type, as described in §7.10.3). Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.
The reasoning is this: you are to think of null for a nullable type as meaning "I do not know what the value is." What is the result of "I don't know" plus one? "I don't know." Thus, the result should be null.
Nullables are never actually null references. They are always object references. Their internal classes override the == and = operators. If they are being compared to null, they'll return the value of the HasValue property.
Why would you expect the compiler to cast it as int when you've declared it as Nullable? The compiler is doing what you've told it to do and null +1 = null.
You'll have to cast explicitly or check x.HasValue before attempting to add an int.
The reason for this is that the compiler creates a 'lifted' operator for nullable types - in this case it is something like:
public static int? operator +(int? a, int? b)
{
return (a == null || b == null) ? (int?)null : a.Value + b.Value
}
I think if you try to assign the result to a non-nullable value, the compiler will be forced to use the non-nullable overload and convert x to an int.
e.g. int i = x + 1; //throws runtime exception
Unfortunately it doesn't. The X in x = X + 1 is null as in the first line so you're adding 1 to null, which equals null.
As it's a nullable int, you can use x.HasValue to check if it has a value, and then x.Value to get the actual int value out
Regardless of whether x is actually never null, that's not even the point.
The point is, when have you ever seen a NullReferenceException when trying to perform an addition?
The following example doesn't throw a NullReferenceException either and is perfectly valid.
string hello = null;
string world = "world";
string hw = hello+world;
You would only get a NullReferenceException if you try to access a member on an object that is null.
int? can never be null because it is a struct. Structs live on the stack and the stack does not handle null well.
See What is a NullPointerException, and how do I fix it?
Also, the nullable types have 2 very useful properties : HasValue, Value
This code:
if (x != null)
{
return (int) x;
}
Should be refactored to this:
if (x.HasValue)
{
return x.Value;
}