How to cast a null boolean from the datareader in C#? - c#

I am trying to cast a null boolean from the database using this method:
bool? primaryFlag = reader["primaryflag"] is DBNull ? null: (bool?)reader["primaryflag"];
I keep getting a Specified Cast Invalid Exception. What is wrong with the method I'm using?

You cannot cast it to a Nullable<bool> directly. But you can use the as operator:
bool? primaryFlag = reader["primaryflag"] as bool?;
This works because the cast fails if the value is DBNull.Value, so it will correctly assign a bool? that is null.
or this less elegant version:
bool? primaryFlag = null;
int colOrdinal = reader.GetOrdinal("primaryflag");
if(!reader.IsDBNull(colOrdinal))
primaryFlag = reader.GetBoolean(colOrdinal);

The problem is that the value in the reader is never a bool?.
Of course, if you cast to a bool, you'll get an error on your ternary, because there's no common type that the compiler can infer. I use a simple trick instead:
reader["primaryFlag"] is DBNull ? default(bool?) : (bool)reader["primaryFlag"];
default(bool?) means exactly the same thing as null in runtime, but it makes the null "typed", as far as the compiler is concerned.
It's also pretty handy to have this as an extension method, so you can just do something like
reader.GetNullable<bool>("primaryFlag")

There a 2 logical solutions:
1 is casting the DB value to the desired task:
bool? primaryFlag = (bool?)reader["primaryflag"]
2 is more simular to you approach:
bool? primaryFlag = reader["primaryflag"] is DBNull ? (bool?) null: (bool)reader["primaryflag"];

You have to also cast the null value with (bool?) null.

Related

cannot implicitly convert type 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?)

Error : cannot implicitly convert type 'bool?' to 'bool'. An explicit
conversion exists (are you missing a cast?)
Code :
Test obj = new Test();
obj.IsDisplay = chkDisplay.IsChecked;
but when I use this method to cast the property into a bool then there is no error.
Test obj = new Test();
obj.IsDisplay = (bool) chkDisplay.IsChecked;
I would like to know why I need to cast this bool to bool?
As the others stated bool? is not equal to bool. bool? can also be null, see Nullable<t> (msdn).
If you know what the null state wants to imply, you easily can use the ?? - null-coalescing operator (msdn) to convert your bool? to bool without any side effects (Exception).
Example:
//Let´s say "chkDisplay.IsChecked = null" has the same meaning as "chkDisplay.IsChecked = false" for you
//Let "check" be the value of "chkDisplay.IsChecked", unless "chkDisplay.IsChecked" is null, in which case "check = false"
bool check = chkDisplay.IsChecked ?? false;
You've declared IsChecked as a bool? (Nullable<bool>). A nullable boolean can be either true, false or null. Now ask yourself: If IsChecked was null, then what value should be assigned to IsDisplay (which can only take a true or false)? The answer is that there is no correct answer. An implicit cast here could only produce hidden trouble, which is why the designers decided to only allow an explicit conversion and not an implicit one.
I'm facing your question when I'm using the null check operator ?.:
if (!RolesList?.Any()) //Not accepted: cannot convert bool? to bool
So I'm using this instead
if (RolesList?.Any() != true)
//value is null or false
In your case you should set it like so:
obj.IsVisible = chkDisplayStuff.IsChecked ?? false;
bool? is not a bool. It is in reality a Nullable<bool>
http://msdn.microsoft.com/en-us/library/b3h38hb0(v=vs.110).aspx
If you need the bool value then you should either cast like you are doing or call the .Value property on the bool?. There is also a .HasValue property you can check to make sure that it is not null.
If IsChecked is null, this line will error.
obj.IsDisplay = (bool) chkDisplay.IsChecked;
bool is not equal to bool?.
bool can take two values, true and false.
bool? can take three, true, false, and null.
That is why they are different.
You can use below code
obj.IsDisplay = chkDisplay.IsChecked == true?true:false;
chkDisplay.IsChecked is of type bool?. Which means it can hold values true, false and null.
However, obj.IsDisplay is of type bool. Which means it can only hold true or false.
Hence you have to explicitly cast it to type bool. However, this will still throw an exception if, the value you are trying to cast to bool is null.
bool? nullableBool = null;
bool notNullableBool = (bool)nullableBool; //This will throw InvalidOperationException
Try this
if (asset.IsUp ?? false)
cast your nullable value to value type
[HttpPost]
public ActionResult Index(bool? checkOffAge)
{
if (checkOffAge != null) {
model.CheckOffAge =(bool)checkOffAge;
}
}

Ternary Operator Unexpected Result

Can someone comment on the issue I'm having. A ternary operator throws an error and the argument here is that if it evaluates to null then it should ignore the part after the colon. The Watch set up for this indicates an exception:
Int32.Parse(SQLDataReader["TrayId"].ToString())' threw an exception of Type 'System.FormatException
suggesting that it can't convert a null to a string. Is this how it works?
ShipmentId = SQLDataReader["ShipmentId"] == DBNull.Value ? 0 : Int32.Parse(SQLDataReader["ShipmentId"].ToString()),
The column ShipmentId is an integer, but it is also nullable, which means that the c# type is int?.
The error boils down to this code:
Int32.Parse((string)null)
The parsing gives up because you can't turn null into an int.
To fix this, use TryParse.
int ShipmentId = 0;
int.TryParse(SQLDataReader["ShipmentId"].ToString(), out ShipmentId);
This will cover if the value is null, or if for some strange reason the value can't actually be converted to an int (like "asdf121343fds").
It's recommended that for comparisons with DBNull, you use the DBNull.Value.Equals method, as described on this page: http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx
ShipmentId = DBNull.Value.Equals(SQLDataReader["ShipmentId"]) ? 0 : Int32.Parse(SQLDataReader["ShipmentId"].ToString());

C#.net can't assign null to a variable in an inline if statement

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.

Using null-coalescing as a replacement for try catch block

How come I get an invalid cast exception when trying to set a NULL value returned from the database inside Comments which is of type Int32.
I am trying to replace this:
try
{
objStreamItem.Comments = (Int32)sqlReader["Comments"];
if (objStreamItem.Comments > 0) {
listComments = Comment.GetAll(objStreamItem.Id);
}
}
catch (InvalidCastException)
{
// Execute if "Comments" returns NULL
listComments = null;
objStreamItem.Comments = 0;
}
With this:
Comments = ((Int32?)sqlReader["Comments"]) ?? 0
The two are in different contexts, but you should get the idea. Instead of using a try catch block I am trying to solve this in a more elegant way.
Thanks.
UPDATE
It is stored as a nullable integer in the database.
public int? Comments
{
get;
set;
}
I just want to thank everyone who answered or posted on this question, everything was very informative. thanks!
Your SQL reader is returning DBNull when the value is null; There's no conversion from DBNull to int?, and the null-coalescing operator doesn't recognize DBNull.Value as something that needs to be coalesced.
EDIT 3
(Another problem with your original code: It will assume that "Comments" returned null if "Comments" is non-null but GetAll() throws an InvalidCastException.)
As hvd points out, you can use the as operator with nullable types:
objStreamItem.Comments = sqlReader["Comments"] as int?;
listComments = (objStreamItem.Comments ?? 0) > 0 ? Comment.GetAll(objStreamItem.ID) : null;
You could save yourself from all of this, however, if you simply defined Comment.GetAll() to return an empty list or a null reference when the ID you pass to it has no comments.
I suppose a ternary expression is the way to go here
objStreamItem.Comments = sqlReader["Comments"] is DBNull ? 0 : (Int32)sqlReader["Comments"] ;
You could also store the return value of sqlReader["Comments"] in a variable first to shorten the expression
var comments = sqlReader["Comments"];
objStreamItem.Comments = comments is DBNull ? 0 : (Int32)comments;
The ?? operator checks for null, but sqlReader["Comments"] won't ever be null. It will either be an Int32, or a DBNull. You can cast null to Int32?, but you cannot do so with DBNull.Value. You can use sqlReader["Comments"] as Int32? instead, which checks if the result can be converted to Int32, and if not, assigns null.
That statement tries to perform the cast before coalescing the values. You need to add parenthesis. Judging by your example above, it also looks like the field is an int rather than an int?:
Comments = (Int32)(sqlReader["Comments"] ?? 0);

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