Static members of nullable types - c#

In c# a value-type cannot have a value of null, however you can enable this by appending a question mark.
e.g.
int intCannotBeNull = 1;
int? intCanBeNull = null;
Additionally, in C# many value types have static members so you can do this for example:
string strValue = "123";
intCannotBeNull = int.Parse(strValue);
However you can't do either of these:
intCanBeNull = int?.Parse(strValue);
intCanBeNull = (int?).Parse(strValue);
C# gets confused. Is there a valid syntax that means strValue could be null or a valid integer value and have the assignment work?
I know there are easy workarounds, for example:
intCanBeNull = (strValue == null) ? null : (int?)int.Parse(strValue);
and other variants of the same thing but that's just messy...

int? is syntactic sugar for Nullable<int>. You are asking about Nullable<int>.Parse. There is no such method. That is where your confusion lies.

Parse will not handle null values, It will throw exception. You have to use either TryParse or Convert class to parse
Convert.ToInt32(int or int?)
This applies for long, float, decimal etc..

int? is in fact Nullable<int>. That Nullable<T> struct doesn't have the methods of the T class. Hence, you have to do it yourself.
In the case of int?, you could try something like this:
string s = "1";
int? result;
if (string.IsNullOrEmpty(s))
{
result = null;
}
else
{
int o; // just a temp variable for the `TryParse` call
if (int.TryParse(s, out o))
{
result = o;
}
else
{
result = null;
}
}
// use result

Related

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
}

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;

cannot convert type 'string' to 'int?' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion or null type conversion

C# accepts the following:
object o = "hello";
int? i = o as int?;
if (i == null) {
// o was not a boxed int
}
else {
// Can use i.Value to recover the original boxed value
}
But not
String o = "hello";
int? i = o as int?;
if (i == null) {
// o was not a boxed int
}
else {
// Can use i.Value to recover the original boxed value
}
I'm just wondering about the behaviour of the keyword as in C#.
The same as in Java this would fail:
Object test1 = "hello";
Integer test2 = (Integer) test1;
String test3 = "hello";
Integer test4 = (Integer) test3; //compilation error
The compiler knows that a string can never be an int? so it tells you that. That doesn't mean that int? isn't useful. Your attempted use case is far from the normal one. The normal one is "I want to represent an integer and the possibility that the value is missing/unknown". For that, int? works extremely well.
Why would you expect your original code to work? Why would it be helpful?
Note that you can use as with nullable types, for unboxing:
object o = "hello";
int? i = o as int?;
if (i == null)
{
// o was not a boxed int
}
else
{
// Can use i.Value to recover the original boxed value
}
EDIT: Having seen your comment, you don't use as to parse things. You probably want to use int.TryParse:
string text = "123":
int value;
if (int.TryParse(text, out value))
{
Console.WriteLine("Parsed successfully: {0}", value);
}
else
{
Console.WriteLine("Unable to parse text as an integer");
}
If you're sure the string is meant to be an integer (i.e. it's a bug otherwise) then you can just use int.Parse:
int value = int.Parse(text);
That will throw an exception if the parsing fails.
Note also that both of these methods allows you to specify a format provider (usually a culture info) which allows you to express how numbers are expressed in that format (e.g. thousands separators).
EDIT: In answer to your new question, the compiler prevents this because it knows a string can't possibly be a boxed int - the conversion will never ever succeed. When it only knows that the original value is an object, it might succeed.
For instance, suppose I said to you, "Here's a shape: is it a square?" That's a sensible question. It's reasonable to ask it: you can't tell without looking at the shape.
If, however, I said: "Here's a triangle: is it a square?" Then you'd be reasonably entitled to laugh in my face, as a triangle can't possibly be a square - the question doesn't make sense.
int? means a nullable integer type, not an int that could contain any other type of variable.
If you want a variable type that could contain an int or a string, you'd have to use an object, or a string I suppose, and then live a life filled with type casting. I don't know why you would want to do that, though.
int? allows you to store any integer value, or a null value. Which is useful when say the answer to the question "How many orders has this person placed" is legitimately "I don't know" instead of a number of orders, or zero which would be "I know for a fact this person has never placed an order".
I want to add some further information.
An other case, why the cast is invalid and the compiler throws an error on compilation is, that System.String is marked as sealed. So the compiler knows from which types System.String inherites and to which types you can cast the string using the as-operator.
Due to the keyword sealed, the compiler also knows that you cannot inherit from System.String to add functionality or implement some additional interfaces.
The code below is an example and the compiler will throw the following error on compilation
Cannot convert type 'SealedClass' to
'ICastToInterface' via a reference
conversion, boxing conversion,
unboxing conversion, wrapping
conversion, or null type conversion
public class UnsealedClass {
// some code
}
public sealed class SealedClass {
// some code
}
public interface ICastToInterface {
// some code
}
public class Test {
public Test() {
UnsealedClass unsealedClass = new UnsealedClass();
SealedClass sealedClass = new SealedClass();
ICastToInterface unsealedCast = unsealedClass as ICastToInterface; // This works fine
ICastToInterface sealedCast = sealedClass as ICastToInterface; // This won´t compile, cause SealedClass is sealed
}
}
but you can check the value of null and set it to null.
int? blah;
if (blah == null)
{}
int? is a nullable integer, it has nothing to do with casting and the as keyword. "String" is a string type object, which is not convertible to an int (nullable or non-nullable).
The as Keyword is virtually the same as casting using brackets except it will not return an error, it will set the object to null:
int i = 1;
object o = i; //boxing
int j = (int)o; //unboxing
This first example works as the object assigned to o is an int.
Now consider:
string i = "MyString";
object o = MyString;
int j = (int)o //unboxing raises exception
int j = o as int; //raises compilation Error as int is not nullable
int? j = o as int?; /// o == null
I hope that that helps to explain the difference between the two concepts.
Richard

Better way to cast object to int

This is probably trivial, but I can't think of a better way to do it. I have a COM object that returns a variant which becomes an object in C#. The only way I can get this into an int is
int test = int.Parse(string.Format("{0}", myobject))
Is there a cleaner way to do this? Thanks
You have several options:
(int) — Cast operator. Works if the object already is an integer at some level in the inheritance hierarchy or if there is an implicit conversion defined.
int.Parse()/int.TryParse() — For converting from a string of unknown format.
int.ParseExact()/int.TryParseExact() — For converting from a string in a specific format
Convert.ToInt32() — For converting an object of unknown type. It will use an explicit and implicit conversion or IConvertible implementation if any are defined.
as int? — Note the "?". The as operator is only for reference types, and so I used "?" to signify a Nullable<int>. The "as" operator works like Convert.To____(), but think TryParse() rather than Parse(): it returns null rather than throwing an exception if the conversion fails.
Of these, I would prefer (int) if the object really is just a boxed integer. Otherwise use Convert.ToInt32() in this case.
Note that this is a very general answer: I want to throw some attention to Darren Clark's response because I think it does a good job addressing the specifics here, but came in late and wasn't voted as well yet. He gets my vote for "accepted answer", anyway, for also recommending (int), for pointing out that if it fails (int)(short) might work instead, and for recommending you check your debugger to find out the actual runtime type.
The cast (int) myobject should just work.
If that gives you an invalid cast exception then it is probably because the variant type isn't VT_I4. My bet is that a variant with VT_I4 is converted into a boxed int, VT_I2 into a boxed short, etc.
When doing a cast on a boxed value type it is only valid to cast it to the type boxed.
Foe example, if the returned variant is actually a VT_I2 then (int) (short) myObject should work.
Easiest way to find out is to inspect the returned object and take a look at its type in the debugger. Also make sure that in the interop assembly you have the return value marked with MarshalAs(UnmanagedType.Struct)
Convert.ToInt32(myobject);
This will handle the case where myobject is null and return 0, instead of throwing an exception.
Use Int32.TryParse as follows.
int test;
bool result = Int32.TryParse(value, out test);
if (result)
{
Console.WriteLine("Sucess");
}
else
{
if (value == null) value = "";
Console.WriteLine("Failure");
}
Maybe Convert.ToInt32.
Watch out for exception, in both cases.
var intTried = Convert.ChangeType(myObject, typeof(int)) as int?;
I am listing the difference in each of the casting ways. What a particular type of casting handles and it doesn't?
// object to int
// does not handle null
// does not handle NAN ("102art54")
// convert value to integar
int intObj = (int)obj;
// handles only null or number
int? nullableIntObj = (int?)obj; // null
Nullable<int> nullableIntObj1 = (Nullable<int>)obj; // null
// best way for casting from object to nullable int
// handles null
// handles other datatypes gives null("sadfsdf") // result null
int? nullableIntObj2 = obj as int?;
// string to int
// does not handle null( throws exception)
// does not string NAN ("102art54") (throws exception)
// converts string to int ("26236")
// accepts string value
int iVal3 = int.Parse("10120"); // throws exception value cannot be null;
// handles null converts null to 0
// does not handle NAN ("102art54") (throws exception)
// converts obj to int ("26236")
int val4 = Convert.ToInt32("10120");
// handle null converts null to 0
// handle NAN ("101art54") converts null to 0
// convert string to int ("26236")
int number;
bool result = int.TryParse(value, out number);
if (result)
{
// converted value
}
else
{
// number o/p = 0
}
There's also TryParse.
From MSDN:
private static void TryToParse(string value)
{
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
Console.WriteLine("Converted '{0}' to {1}.", value, number);
}
else
{
if (value == null) value = "";
Console.WriteLine("Attempted conversion of '{0}' failed.", value);
}
}
Strange, but the accepted answer seems wrong about the cast and the Convert in the mean that from my tests and reading the documentation too it should not take into account implicit or explicit operators.
So, if I have a variable of type object and the "boxed" class has some implicit operators defined they won't work.
Instead another simple way, but really performance costing is to cast before in dynamic.
(int)(dynamic)myObject.
You can try it in the Interactive window of VS.
public class Test
{
public static implicit operator int(Test v)
{
return 12;
}
}
(int)(object)new Test() //this will fail
Convert.ToInt32((object)new Test()) //this will fail
(int)(dynamic)(object)new Test() //this will pass
You can first cast object to string and then cast the string to int;
for example:
string str_myobject = myobject.ToString();
int int_myobject = int.Parse(str_myobject);
this worked for me.
int i = myObject.myField.CastTo<int>();
This worked for me, returning 0 also when myobject contains a DBNull
int i = myobject.ToString().Cast<int>().FirstOrDefault();

Categories

Resources