Assign nullable int to int in ternary operator - c#

I have a class say
class Test
{
int? a;
int b;
}
Now i m creating a object of test class
Test objTest = new Test();
objTest.b = objTest.a;
Here it throws error cannot implicitly convert int? to int.
So i came up with solution
objTest.b = ObjTest.a ?? 0;
Works fine Here But !!!
objTest.b = objTest.a == null ? 0 : objTest.a
Fails ..
Why basically both doing the same checking null value and assign value accordingly

You would still need to cast a to an int in your second example.
objTest.b = objTest.a == null ? 0 : (int)objTest.a
will compile. But just do it the first way you came up with.

Related

Checking if JValue is null

Why this code doesn't run, I want to check if JSON contains integer for key PurchasedValue or not? () :
public PropertyInfo(Newtonsoft.Json.Linq.JToken jToken)
{
this.jToken = jToken;
int PurchasedValue = (int)(jToken["PurchasedValue"].Value ?? 0);
}
the error is :
Error CS0019: Operator `??' cannot be applied to operands of type `method group' and `int' (CS0019)
From my understanding jToken["PurchasedValue"] is a nullable value.
You have to use
int PurchasedValue = (int)(jToken["PurchasedValue"]?? 0);
nullableObj.Value can be only used without error only when there is a value for the nullableObj
Otherwise You can use like
int PurchasedValue = jToken["PurchasedValue"].HasValue?jToken["PurchasedValue"].Value: 0;
This May not even need type casting
You can compare the token type:
var purchasedValueToken = jToken["PurchasedValue"];
int purchasedValue = purchasedValueToken.Type == JTokenType.Null ? 0 : purchasedValueToken.Value<int>();
Well, there are couple of things here :
The jToken["PurchasedValue"] could return anything so a type check would be preferable.
You can change your code as following:
public PropertyInfo(Newtonsoft.Json.Linq.JToken jToken)
{
this.jToken = jToken;
int PurchasedValue = jToken["PurchasedValue"] is int ? jToken["PurchasedValue"] : 0;
}

Use "as" operator to test integer type in Page.RouteData.Values

In my code I have registered route in global.asax like the following:
void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute(
"product",
"product/{id}",
"~/index.aspx"
);
then in my index.aspx page, I want to test the {id} value whether it is integer:
if (Page.RouteData.Values["id"] as int? != null)
//always evaluate as null even id is an integer in the URL, ex: /product/1
I understand I can use some other methods (such as int.TryParse or this ) to achieve the same goal, but would using a "as" make sense in this case?
The way to go depends on what is really stored in Values["id"]. If it is in fact an int, you can test for int with Values["id"] is int. The Values[] property is typed as object. Therefore it can be null. But this does NOT mean, that the stored int is a Nullable<int>. (see my update below.)
If you assign an int (and all other non-reference types) to an object variable or property, it will be boxed. I.e. it will be packed into an object of the corresponding type. int or System.Int32 exists as value type as well as a boxed and immutable System.Int32 reference type. Because of its immutability, you don't notice that it is a reference type. An int can be boxed with object obj = 5; and unboxed with int i = (int)obj;.
On the other hand, if the id was stored as string then you would have to convert it to a number
int id;
if (Int32.TryParse((string)Page.RouteData.Values["id"], out id)) {
// use id here
}
UPDATE:
There seems to be some confusion with null and Nullable<T>.
int? i; // Same as Nullable<int> or Nullable<System.Int32> or System.Int32?
object obj;
bool test;
i = null;
test = i.HasValue; // ==> false
test = i == null; // ==> true
// Now comes the strange part
obj = 5; // The int is boxed here.
// Debugger shows type of obj as "object {int}"
test = obj is int; // ==> true
test = obj is int?; // ==> true
int x = (int)obj; // ==> 5, the int is unboxed here.
// But
obj = null;
// Debugger shows type of obj as "object"
test = obj is int; // ==> false
test = obj is int?; // ==> false
test = obj == null; // ==> true
// And
i = 5;
obj = i; // i is a Nullable<int>
// Debugger shows type of obj as "object {int}"
test = obj is int; // ==> true
test = obj is int?; // ==> true
test = obj == null; // ==> false
i = null;
obj = i;
// Debugger shows type of obj as "object"
test = obj is int; // ==> false
test = obj is int?; // ==> false
test = obj == null; // ==> true
Both obj is int and obj is int? return true if obj contains an int number but both return false if obj contains null! A null Nullable<int> is converted to (object)null when asssigned to obj and is no more Nullable<int>.
The debugger shows the type of obj as object {int} when there is a number stored, no matter whether an int or an int? was assigned! The type of obj is object when null is stored.
So Chuong Le is in fact right!
I would recommend that you use Int.TryParse, because the value is most likely going to be a string. Don't use the Int.Parse because you will also have to handle the exception and you generally want to avoid coding things that could throw exceptions (even if you're handling them).
Using as is not really a good solution since it forces you to use nullable int; if you take the is route, then it's almost guaranteed not to work when the passed in value is a string type.
Regarding the is debate, I ran this in VS:
string value = "42";
object answerToUniverse = value;
if (answerToUniverse is int)
{
Console.WriteLine("It's an integer!");
}
else
{
Console.WriteLine("It's NOT an integer!");
}
The result was: It's NOT an integer!
Looks like you want to check the value rather than the type meaning you don't really care what the type is.
In such case, this is the best approach I can recommend:
object idValue = Page.RouteData.Values["id"];
int dummy;
if (idValue != null && Int32.TryParse(idValue.ToString(), out dummy))
{
//value is integer!
}
This way it doesn't matter what the type is; if it's integer, double, string or even complex type with proper ToString() override, it will work.
as is a safe cast. It will try and cast the provided value to the desired type, returning null instead of throwing an exception when a standard cast would.
Therefore unless Page.RouteData.Values["id"] was an integer object this would not work and you need to user the alternative methods you suggested.
One was could be to use an extension method
public static class IntExtensions {
public static int? AsInt(this string source) {
int result;
return (int.TryParse(source,out result)) ? (int?)null : result;
}
public static bool IsInt(this string source) {
return source.AsInt.HasValue;
}
}
Allowing you to do
if (Page.RouteData.Values["id"].IsInt())
Perhaps you actually want to do this,
var idString = Page.RouteData.Values["id"] as string;
int id;
if (int.TryParse(idString, out id))
{
// id is now a valid number
}
else
{
// your types are confused
}

What's the best implementation of safe navigation operator

Is there an operator in C# that behaves like the safe navigation operator in groovy?
For instance, in groovy, doing something like this will prevent it from getting a NullPointerException if SessionData.CurrentSeminar is null.
int respId = SessionData.CurrentSeminar?.SeminCbaRespId;
How is this accomplished with C#?
That operator does not exist in C#. You could do it with an inline-if
int respId = SessionData.CurrentSeminar != null ?
SessionData.CurrentSeminar.SeminCbaRespId : default(int);
or as an extension method.
var respId = SessionData.CurrentSeminar.GetSeminCbaRespId();
public static int GetSeminCbaRespId(this typeofCurrentSeminar CurrentSeminar)
{
return CurrentSeminar != null ? CurrentSeminar.SeminCbaRespId : default(int);
}
Maybe workaround like this?
int respId= ReferenceEquals(SessionData.CurrentSeminar,null)?-1:SessionData.CurrentSeminar.SeminCbaRespId;
The closest operator is ?:, but it's not as sugary.
So, you could do:
int respId = SessionData.CurrentSeminar != null ? SessionData.CurrentSeminar.SeminCbaRespId : 0; // if 0 is the "null" value
There is no operator for this, but you can get close. Try the one from this answer:
int respId = SessionData.CurrentSeminar.NullOr(s => s.SeminCbaRespId) ?? 0;
This gets extra useful if you need to chain several of them:
var elem = xml.Element("abc")
.NullOr(x => x.Element("def"))
.NullOr(x => x.Element("blah");

C# IsNullOrZero

This pattern comes up very frequently in my code:
x= x== 0? 1: x;
//or
x= x==null? 1: x;
However it happens that sometimes x is a long expression and I'd have to use intermediate variables. That's just useless boilerplate code. I can cook up a method and call it instead:
Util.IfNullOrZero(x, 1);
But that's just ugly. What is the best way of expressing the pattern? In ruby there is such syntax for when x is nil which gets rid of redundant x's:
x||= 1
I could extend object in a manner
public static class wtf
{
public static T Default<T>(this object o, T d)
{
return o == null ? d : new object[] { o }.Cast<T>().First();
}
}
And then do
object param= null;
int x= param.Default(1);
But that's a bit expensive.
In short how to best make C# do x||= 1 like in ruby?
Update
This is what I cooked up. I'm currently looking for a faster way of using the Template parameter to convert object to T.
public static class MyExtensions
{
public static T d<T>(this object o, T d)
{
return o == null || o.Equals(default(T)) ? d : new object[] { o }.Cast<T>().First();
}
}
In fact the code does three things at once: Casts to default type, checks for default value and also checks for null.
Update 2
return o == null || o.Equals(default(T)) ? d : (T)o; // much simpler and faster
I still think it is a commonality which needs to be included in core language.
Update 3
This is what I finally wrote, taking into account DataTable DBNull types.
public static T d<T>(this object o, T d)
{
return o == null || (o is System.DBNull) || o.Equals(default(T)) ? d : (T)Convert.ChangeType(o, typeof(T));
}
For handling the "==null" case, the null coalesce operator does the trick.
y = x ?? z;
means
if (x == null)
y = z;
else
y = x;
I'm not aware of something that check for both zero and null, writing a method to perform this task might be the best solution. Here it goes:
public static T IsNullOrZero<T>(this T variable, T defaultValue)
{
// defaultValue can't be null, doesn't make sense
if (defaultValue == null) throw new ArgumentException("default value can't be null", "defaultValue");
if (variable == null || variable.Equals(default(T)))
return defaultValue;
return variable;
}
Usage:
x = x.IsNullOrZero(y);
Note: this in fact works on non-numbers too (name might be misleading if dealing with non-numbers... maybe something along the lines of IsNullOrDefault might be a better name).
You can check like
public static bool IsNullOrValue(this int? value, int valueToCheck)
{
return (value??valueToCheck) == valueToCheck;
}
more on here
For checking for null and providing a default value, you can use the ?? operator:
return x ?? new Foo();
That means, if x is null, return new Foo(), else return x. You can use it for reference types and nullable types. For nun-nullable types like int, you still need to explicitly check for 0.
What you want is the Coalesce operator (??), which does just that - if returns the first operand if it's not null, and the second if it is. This will instantiate a new object if the current one is null:
return myObj ?? new MyObject();
Note that the ?? operator works only for classes and reference types, not for ints and other value types that can't be null. There, you'll have to check manually for default, uninitialized values (0 for ints and shorts and stuff, false for bools, and so forth)

Convert null field to zero before converting to int?

In my program, I'm looping through a datatable to get data from each field. One line of my code looks like this:
int LYSMKWh = Convert.ToInt32(resultsDT.Rows[currentRow]["LYSMKWh"]);
Basically, I'm just taking the value that's in the cell and converting it to an int32. I run into a problem, though, when the data in the field is a null. I get an Invalid Cast error message about not being able to convert a "DBNull" to another type.
So, I know that I can just check the value of the field before I try to convert it by doing something like this:
if (resultsDT.Rows[currentRow]["LYSMKWh"] == null)
{
resultsDT.Rows[currentRow]["LYSMKWh"] = 0;
}
But, is there a better way to do this? Is there something I can do "inline" while I'm trying to convert the value without having to resort to using the if ?
EDIT: I did try using this suggested method:
int LYSMKWh = Convert.ToInt32(resultsDT.Rows[currentRow]["LYSMKWh"] ?? "0");
Unfortunately, I still received the Invalid Cast error message with regards to the DBNull type. It was suggested that I could have problems using the ?? operator if the types on either side were different.
Also, since I have complete control over the data that I'm building my datatable with, I changed it so that no null values would be written to any field. So, that pretty much negates the need to convert a null to an int32, in this case. Thanks for all the advice, everyone!
You could do this:
var LYSMKWh =
resultsDT.Rows[currentRow]["LYSMKWh"].Equals(DBNull.Value)
? 0
: Convert.ToInt32(resultsDT.Rows[currentRow]["LYSMKWh"]);
use the ?? operator:
resultsDT.Rows[currentRow][...] ?? "0"
(expecting the field to be a string - if not change the "0")
You may consider using C#'s ?? operator, which checks a value for null and if it's null, assigns a default value to it.
You can use the ?? operator:
object x = null;
int i = (int)(x ?? 0)
You can use a custom convert method:
public static int ConvertToInt32(object value, int defaultValue) {
if (value == null)
return defaultValue;
return Convert.ToInt32(value);
}
You may need overloads that take other types, like string. You may have problems with the ?? operator if the types on either side are different.
You can replace it with a ternary operator:
var rowData = resultsDT.Rows[currentRow]["LYSMKWh"];
int LYSMKWh = rowData != null ? Convert.ToInt32(rowData) : 0;
Alternatively, the ?? operator could work:
int LYSMKWh = Convert.ToInt32(resultsDT.Rows[currentRow]["LYSMKWh"] ?? 0);
But I think that's less readable.
You can use extension Method.
int LYSMKWh = resultsDT.Rows[currentRow]["LYSMKWh"].IfNullThenZero();
Create the below class
public static class Converter
{
public static Int32 IfNullThenZero(this object value)
{
if (value == DBNull.Value)
{
return 0;
}
else
{
return Convert.ToInt32(value);
}
}
}
Check if it's DBNull.Value instead of null:
if (resultsDT.Rows[currentRow]["LYSMKWh"] == DBNull.Value)
{
resultsDT.Rows[currentRow]["LYSMKWh"] = 0;
}
The ternary expression would work like this:
var LYSMKwhField = resultsDT.Rows[currentRow]["LYSMKWh"];
int LYSMKWh = LYSMKwhField != DBNull.Value ? Convert.ToInt32(rowData) : 0;

Categories

Resources