Why can't I cast generic-type with null? [dupl

2020-01-19 05:04发布

问题:

A similar question, but without casting the T parameter.

This does not work

public T GetValueG<T>(string Query)
{
    object value = DBNull.Value;    // Read from Database which can return DBNull
    if (value is DBNull)
        return (T)null;
    else
        return (T)value;
}

Error CS0037 Cannot convert null to 'T' because it is a non-nullable value type


But this works

public T GetValueG<T>(string Query)
{
    object value = DBNull.Value;    // Read from Database which can return DBNull
    if (value is DBNull)
        value = null;

    return (T)value;
}

I know that using constraint type where T: struct will make T to be able to be cast with null directly.

But in the second approach, why does it accept an object which is 100% can be null? Why can't I return null directly without an object or something either?

回答1:

What you're trying to do is wrong. Integers are non-nullable types, meaning you can't return null as a value of int or any other not nullable type (as the name suggests...)

Take for example:

int myInt = null; - your IDE will right away flag it up with integer being a non-nullable type.

What you want to do is use a nullable type of the actual type you're trying to use e.g. int? or bool?.

You should be returning null or default(T) rather than (T)null that doesn't make sense, as you can't cast null to e.g. a class type, it'll throw Object Reference Not Set To An Instance....

I would change your function to the following:

public T GetValueG<T>(string Query)
{

    object value = DBNull.Value;    // Read from Database which can return DBNull
    if (value is DBNull)
        return default(T);  // `return default;` also valid since C# 7.1 

    return (T)value;
}

If a value can be null in your database, then your model should be implementing a nullable of that type to avoid casting exceptions later down the line.

Your function should be called as such GetValueG<int?>("<query>");.

Default values for non-nullables can be found here.

In your code, rather than checking for null values using myInt == null you'd do myNullableInt.HasValue.

Summary

The default keyword. will return null for nullable types by default. and default values for other non-nullable types. as OP needs.

default(bool?) -> null

default(bool) -> false