Detect nullable type - c#

Is it possible to detect a Nullable type (cast into an object) when it is null?
Since Nullable<T> is really a struct I think it should be possible.
double? d = null;
var s = GetValue(d); //I want this to return "0" rather than ""
public string GetValue(object o)
{
if(o is double? && !((double?)o).HasValue) //Not working with null
return "0";
if(o == null)
return "";
return o.ToString();
}

http://msdn.microsoft.com/en-us/library/ms228597(v=vs.80).aspx
Objects based on nullable types are only boxed if the object is
non-null. If HasValue is false, then, instead of boxing, the object
reference is simply assigned to null.
and
If the object is non-null -- if HasValue is true -- then boxing takes
place, but only the underlying type that the nullable object is based
upon is boxed.
So you either have a double or a null.
public string GetValue(object o)
{
if(o == null) // will catch double? set to null
return "";
if(o is double) // will catch double? with a value
return "0";
return o.ToString();
}

You have the method GetValueOrDefault for every Nullable type, isn't it enough ?

Your method currently takes object, which means the nullable value will be boxed... and will no longer be a nullable value. The value of o will either be a boxed value of the non-nullable type, or a null reference.
If at all possible, change your method to be generic:
public string GetValue<T>(T value)
{
// Within here, value will still be a Nullable<X> for whatever type X
// is appropriate. You can check this with Nullable.GetUnderlyingType
}

If o is null then o is double? will be false. No matter the value of your input parameter double? d

From what I understand, if you are trying to detect if ANY object is nullable, this can be written fairly easily.
try this...
public static bool IsNullable(dynamic value)
{
try
{
value = null;
}
catch(Exception)
{
return false;
}
return true;
}
Simple!

Related

.ToString() does not raise an exception on double? or long? while it will raise an exception on null string

I have three properties as follow:-
public Nullable<double> SPEED { get; set; }
public Nullable<Int64> PROCESSORCOUNT { get; set; }
public string CPUNAME { get; set; }
now inside my asp.net mvc5 web application's controller class, if i pass null for the above three variables, as follow:-
query["proSpeed"] = sj.SPEED.ToString();
query["proCores"] = sj.PROCESSORCOUNT.ToString();
query["proType"] = sj.CPUNAME.ToString();
then the toString() will only raise an exception on the null string mainly sj.CPUNAME.ToString();, so can anyone adivce why ToString() will not raise an exception if i try to convert double? or long? that contain null values to string, but it will raise a null reference exception only if the string is null ?
To simplify it:
int? x = null;
string result = x.ToString(); // No exception
Here null isn't a null reference. It's just a null value of the type int?, i.e. a value of type Nullable<int> where HasValue is false.
You're just invoking the Nullable<T>.ToString() method on that value. No null references are involved, so there's no NullReferenceException. The behaviour is documented as:
The text representation of the value of the current Nullable<T> object if the HasValue property is true, or an empty string ("") if the HasValue property is false.
In other words, it's effectively implemented as:
return HasValue ? Value.ToString() : "";
Note that this only works if the compile-time type is the nullable type.
If you end up boxing a null value, you'll end up with a null reference:
object y = x; // Oh noes, now y is a null reference...
string bang = y.ToString(); // so this throws!
Nullable<T> cannot itself be null, its value can. For example, you could implement its ToString method as:
public string override ToString()
{
if (this.HasValue) return this.Value;
else return string.Empty;
}
You can't do the same thing for string, thus if the string is null, a NullReferenceException is raised.
The MSDN Help is fairly clear on this.
The text representation of the value of the current Nullable object
if the HasValue property is true, or an empty string ("") if the
HasValue property is false.

Type checking on Nullable<int>

If have the following method:
static void DoSomethingWithTwoNullables(Nullable<int> a, Nullable<int> b)
{
Console.WriteLine("Param a is Nullable<int>: " + (a is Nullable<int>));
Console.WriteLine("Param a is int : " + (a is int));
Console.WriteLine("Param b is Nullable<int>: " + (b is Nullable<int>));
Console.WriteLine("Param b is int : " + (b is int));
}
When i call this method with null as a parameter, the type check returns false for this parameter. For example this code
DoSomethingWithTwoNullables(5, new Nullable<int>());
results in this output:
Param a is Nullable<int>: True
Param a is int : True
Param b is Nullable<int>: False
Param b is int : False
Is there any way to preserve the type information when using a Nullable and passing null? I know that checking the type in this example is useless, but it illustrates the problem. In my project, I pass the parameters to another method that takes a params object[] array and tries to identify the type of the objects. This method needs to do different things for Nullable<int> and Nullable<long>.
Going straight to the underlying problem, no, you can't do this. A null Nullable<int> has exactly the same boxed representation as a null Nullable<long>, or indeed a 'normal' null. There is no way to tell what 'type' of null it is, since its underlying representation is simply all-zeros. See Boxing Nullable Types for more details.
conceptually, new Nullable<int> is null.
If we generalise, forgetting about Nullable<T>:
string s = null;
bool b = s is string;
we get false. false is the expected value for a type-check on a null value.
You can try using Reflection to achieve this. Relevant article here.
Unfortunately, null does not point to any specific memory location, and thus there is no metadata that you can associate with it to lookup the type. Thus, you cannot gain any additional information about the variable.
Unless I'm misunderstanding the question, you can get the type using GetType(). For example,
int? myNullableInt = null;
Console.WriteLine(myNullableInt.GetValueOrDefault().GetType());
If myNullableInt is null, a default value will be returned. Check the type of this returned value and, in this case, it will return System.Int32. You can do an If..else/Switch check on the returned type to perform the relevant action.
(int? is the same as Nullable<int>)
You can't do this, nor should you want to. Since Nullable<T> is a struct, value-type variables of this type have all the type information you need at compile time. Just use the typeof operator.
On the other hand, you might have a Nullable instance whose type you don't know at compile time. That would have to be a variable whose static type is object or some other reference type. Howver, because a Nullable<T> value boxes to a boxed T value, there's no such thing as a boxed Nullable<T>. That instance whose type your checking will just be a T.
This is why you get the same result for is int and is Nullable<int>. There's no way to distinguish between a boxed int and a boxed int?, because there is no boxed int?.
See Nulls not missing anymore for details.
As it has already been pointed out null has no type. To figure out if something is int? vs long? you need to use reflection to get information about something storing the type. Here is some code that you may be able to use as inspiration (not knowing exactly what you try to achieve the code is a bit weird):
class Pair<T> where T : struct {
public Pair(T? a, T? b) {
A = a;
B = b;
}
public T? A { get; private set; }
public T? B { get; private set; }
}
void DoSomething<T>(Pair<T> pair) where T : struct {
DoMore(pair);
}
void DoMore(params object[] args) {
Console.WriteLine("Do more");
var nullableIntPairs = args.Where(IsNullableIntPair);
foreach (Pair<int> pair in nullableIntPairs) {
Console.WriteLine(pair.A);
Console.WriteLine(pair.B);
}
}
bool IsNullableIntPair(object arg) {
var type = arg.GetType();
return type.IsGenericType
&& type.GetGenericTypeDefinition() == typeof(Pair<>)
&& type.GetGenericArguments()[0] == typeof(int);
}
If you execute the following code
DoSomething(new Pair<int>(5, new int?()));
DoSomething(new Pair<long>(new long?(), 6L));
you get the following output:
Do more
5
null
Do more
You can use typeof :
a == typeof(Nullable<int>) //true
a == typeof(int) //false

What are Nullable Types in C#?

int? _fileControlNo = null;
public int? FileControlNo
{
get { return _fileControlNo; }
set { _fileControlNo = value; }
}
I'm getting a syntax error when I assign null values to the above properties.
objDPRUtils.FileControlNo =sArrElements.Value(3)==null ? null : Convert.ToInt32(sArrElements.Value(3));
Please, can anyone explain to me why the error occurs if I'm able to set null value in valuetype object using Nullable Type.
The results of the conditional operators need to be of the same type or types that can be implicitly convertible to each other.
In your case you have a null and an Int32 - these violate that requirement.
If instead of an Int32 you return a nullable Int32, the null can be implicitly converted to this type and your code will work (or alternatively, cast the null to an int?).
Cast your null to int?
objDPRUtils.FileControlNo =sArrElements.Value(3)==null ? (int?) null : Convert.ToInt32(sArrElements.Value(3));
The conditional operator needs to return result of the same type and in your case its not possible for null
this should work
sArrElements.Value(3)==null ? (int?)null : Convert.ToInt32(sArrElements.Value(3));
Nullable types are exactly what they say they are: simple value types that can also store a null value.
I would suggest that you do not need the last line of code at all. you should be able to get away with:
objDPRUtils.FileControlNo =sArrElements.Value(3);
If you really want to assign another value in case of null, use the null coalescing operator ??
objDPRUtils.FileControlNo =sArrElements.Value(3)??0;
which in this case, would assign the value 0 to the FileControlNo in case of the right hand side being null.
Try to assign directly like this :
objDPRUtils.FileControlNo =sArrElements.Value(3);
Your code mixes types null and Int32 cannnot be mixed in this instance like that. They need to be of the same type.
If you use int.TryParse and only attempt to set the value on success you will achieve the same result and can use HasValue on the field to determine if its null or not which is how nullable types are used typically
Silly example
class Program
{
private static int? _fileControlNo;
static void Main(string[] args)
{
string[] sArrElements = new string[] { "1", "2", "3", null };
int result;
if (int.TryParse(sArrElements[3], out result))
{
FileControlNo = result;
}
if (_fileControlNo.HasValue)
{
// do something here
}
}
public static int? FileControlNo
{
get { return _fileControlNo; }
set { _fileControlNo = value; }
}
}
you will note that your code inside the test for HasValue in this case will never execute because _fileControlNo cannot be set because tryParse always fails (change the indexer and that will change).

Returning nullable string types

So I have something like this
public string? SessionValue(string key)
{
if (HttpContext.Current.Session[key].ToString() == null || HttpContext.Current.Session[key].ToString() == "")
return null;
return HttpContext.Current.Session[key].ToString();
}
which doesn't compile.
How do I return a nullable string type?
String is already a nullable type. Nullable can only be used on ValueTypes. String is a reference type.
Just get rid of the "?" and you should be good to go!
As everyone else has said, string doesn't need ? (which is a shortcut for Nullable<string>) because all reference types (classes) are already nullable. It only applies to value type (structs).
Apart from that, you should not call ToString() on the session value before you check if it is null (or you can get a NullReferenceException). Also, you shouldn't have to check the result of ToString() for null because it should never return null (if correctly implemented). And are you sure you want to return null if the session value is an empty string ("")?
This is equivalent to what you meant to write:
public string SessionValue(string key)
{
if (HttpContext.Current.Session[key] == null)
return null;
string result = HttpContext.Current.Session[key].ToString();
return (result == "") ? null : result;
}
Although I would write it like this (return empty string if that's what the session value contains):
public string SessionValue(string key)
{
object value = HttpContext.Current.Session[key];
return (value == null) ? null : value.ToString();
}
You can assign null to a string since its a reference type, you don't need to be able to make it nullable.
String is already a nullable type. You don't need the '?'.
Error 18 The type 'string' must be a
non-nullable value type in order to
use it as parameter 'T' in the generic
type or method 'System.Nullable'
string is already nullable on its own.

Nullable type as a generic parameter possible?

I want to do something like this :
myYear = record.GetValueOrNull<int?>("myYear"),
Notice the nullable type as the generic parameter.
Since the GetValueOrNull function could return null my first attempt was this:
public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : class
{
object columnValue = reader[columnName];
if (!(columnValue is DBNull))
{
return (T)columnValue;
}
return null;
}
But the error I'm getting now is:
The type 'int?' must be a reference type in order to use it as parameter 'T' in the generic type or method
Right! Nullable<int> is a struct! So I tried changing the class constraint to a struct constraint (and as a side effect can't return null any more):
public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct
Now the assignment:
myYear = record.GetValueOrNull<int?>("myYear");
Gives the following error:
The type 'int?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method
Is specifying a nullable type as a generic parameter at all possible?
Change the return type to Nullable<T>, and call the method with the non nullable parameter
static void Main(string[] args)
{
int? i = GetValueOrNull<int>(null, string.Empty);
}
public static Nullable<T> GetValueOrNull<T>(DbDataRecord reader, string columnName) where T : struct
{
object columnValue = reader[columnName];
if (!(columnValue is DBNull))
return (T)columnValue;
return null;
}
public static T GetValueOrDefault<T>(this IDataRecord rdr, int index)
{
object val = rdr[index];
if (!(val is DBNull))
return (T)val;
return default(T);
}
Just use it like this:
decimal? Quantity = rdr.GetValueOrDefault<decimal?>(1);
string Unit = rdr.GetValueOrDefault<string>(2);
Just do two things to your original code – remove the where constraint, and change the last return from return null to return default(T). This way you can return whatever type you want.
By the way, you can avoid the use of is by changing your if statement to if (columnValue != DBNull.Value).
Disclaimer: This answer works, but is intended for educational purposes only. :) James Jones' solution is probably the best here and certainly the one I'd go with.
C# 4.0's dynamic keyword makes this even easier, if less safe:
public static dynamic GetNullableValue(this IDataRecord record, string columnName)
{
var val = reader[columnName];
return (val == DBNull.Value ? null : val);
}
Now you don't need the explicit type hinting on the RHS:
int? value = myDataReader.GetNullableValue("MyColumnName");
In fact, you don't need it anywhere!
var value = myDataReader.GetNullableValue("MyColumnName");
value will now be an int, or a string, or whatever type was returned from the DB.
The only problem is that this does not prevent you from using non-nullable types on the LHS, in which case you'll get a rather nasty runtime exception like:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot convert null to 'int' because it is a non-nullable value type
As with all code that uses dynamic: caveat coder.
I think you want to handle Reference types and struct types.
I use it to convert XML Element strings to a more typed type.
You can remove the nullAlternative with reflection.
The formatprovider is to handle the culture dependent '.' or ',' separator in e.g. decimals or ints and doubles.
This may work:
public T GetValueOrNull<T>(string strElementNameToSearchFor, IFormatProvider provider = null )
{
IFormatProvider theProvider = provider == null ? Provider : provider;
XElement elm = GetUniqueXElement(strElementNameToSearchFor);
if (elm == null)
{
object o = Activator.CreateInstance(typeof(T));
return (T)o;
}
else
{
try
{
Type type = typeof(T);
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
{
type = Nullable.GetUnderlyingType(type);
}
return (T)Convert.ChangeType(elm.Value, type, theProvider);
}
catch (Exception)
{
object o = Activator.CreateInstance(typeof(T));
return (T)o;
}
}
}
You can use it like this:
iRes = helper.GetValueOrNull<int?>("top_overrun_length");
Assert.AreEqual(100, iRes);
decimal? dRes = helper.GetValueOrNull<decimal?>("top_overrun_bend_degrees");
Assert.AreEqual(new Decimal(10.1), dRes);
String strRes = helper.GetValueOrNull<String>("top_overrun_bend_degrees");
Assert.AreEqual("10.1", strRes);
Multiple generic constraints can't be combined in an OR fashion (less restrictive), only in an AND fashion (more restrictive). Meaning that one method can't handle both scenarios. The generic constraints also cannot be used to make a unique signature for the method, so you'd have to use 2 separate method names.
However, you can use the generic constraints to make sure that the methods are used correctly.
In my case, I specifically wanted null to be returned, and never the default value of any possible value types. GetValueOrDefault = bad. GetValueOrNull = good.
I used the words "Null" and "Nullable" to distinguish between reference types and value types. And here is an example of a couple extension methods I wrote that compliments the FirstOrDefault method in System.Linq.Enumerable class.
public static TSource FirstOrNull<TSource>(this IEnumerable<TSource> source)
where TSource: class
{
if (source == null) return null;
var result = source.FirstOrDefault(); // Default for a class is null
return result;
}
public static TSource? FirstOrNullable<TSource>(this IEnumerable<TSource?> source)
where TSource : struct
{
if (source == null) return null;
var result = source.FirstOrDefault(); // Default for a nullable is null
return result;
}
Just had to do something incredible similar to this. My code:
public T IsNull<T>(this object value, T nullAlterative)
{
if(value != DBNull.Value)
{
Type type = typeof(T);
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
{
type = Nullable.GetUnderlyingType(type);
}
return (T)(type.IsEnum ? Enum.ToObject(type, Convert.ToInt32(value)) :
Convert.ChangeType(value, type));
}
else
return nullAlternative;
}
Incase it helps someone - I have used this before and seems to do what I need it to...
public static bool HasValueAndIsNotDefault<T>(this T? v)
where T : struct
{
return v.HasValue && !v.Value.Equals(default(T));
}
This may be a dead thread, but I tend to use the following:
public static T? GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct
{
return reader[columnName] as T?;
}
The shorter way :
public static T ValueOrDefault<T>(this DataRow reader, string columnName) =>
reader.IsNull(columnName) ? default : (T) reader[columnName];
return 0 for int, and null for int?
I just encountered the same problem myself.
... = reader["myYear"] as int?; works and is clean.
It works with any type without an issue. If the result is DBNull, it returns null as the conversion fails.
I know this is old, but here is another solution:
public static bool GetValueOrDefault<T>(this SqlDataReader Reader, string ColumnName, out T Result)
{
try
{
object ColumnValue = Reader[ColumnName];
Result = (ColumnValue!=null && ColumnValue != DBNull.Value) ? (T)ColumnValue : default(T);
return ColumnValue!=null && ColumnValue != DBNull.Value;
}
catch
{
// Possibly an invalid cast?
return false;
}
}
Now, you don't care if T was value or reference type. Only if the function returns true, you have a reasonable value from the database.
Usage:
...
decimal Quantity;
if (rdr.GetValueOrDefault<decimal>("YourColumnName", out Quantity))
{
// Do something with Quantity
}
This approach is very similar to int.TryParse("123", out MyInt);
Here is an extension method I've used for years:
public static T GetValue<T>(this DbDataReader reader, string columnName)
{
if (reader == null) throw new ArgumentNullException(nameof(reader));
if (string.IsNullOrWhiteSpace(columnName))
throw new ArgumentException("Value cannot be null or whitespace.", nameof(columnName));
// do not swallow exceptions here - let them bubble up to the calling API to be handled and/or logged
var index = reader.GetOrdinal(columnName);
if (!reader.IsDBNull(index))
{
return (T)reader.GetValue(index);
}
return default;
}

Categories

Resources