int? 竟然真的可以是 null!.NET/C# 确定可空值类型 Nullable 实例的真实类型
使用 Nullable<T>
我们可以为原本不可能为 null
的值类型像引用类型那样提供一个 null
值。不过注意:Nullable<T>
本身也是个 struct
,是个值类型哦。这意味着你随时可以调用 .HasValue
这样的方法,而不用担心会出现 NullReferenceException
。
等等!除了本文提到的一些情况。
Nullable 中的 null
注意看以下的代码。我们创建了一个值为 null
的 int?
,然后依次输出 value
的值、value.GetType()
。
你觉得可以得到什么结果呢?
public class Program
{
public static void Main(string[] args)
{
int? value = GetValue(null);
Console.WriteLine($"value = {value}");
Console.WriteLine($"type = {value.GetType()}");
Console.WriteLine($"TYPE = {typeof(int?)}");
Console.ReadLine();
}
private static int? GetValue(int? source) => source;
}
结果是……
果是……
是……
……
…
崩掉了……
那么我们在 value
后面加个空传递运算符:
-- Console.WriteLine($"type = {value.GetType()}");
++ Console.WriteLine($"type = {value?.GetType()}");
现在再次运行,我们确认了 value?.GetType()
的值为 null
;而 typeof(int?)
的类型为 Nullable<Int32>
。
然而,我们现在将 value
的值从 null
改为 1
:
-- int? value = GetValue(null);
++ int? value = GetValue(1);
竟然 value.GetType()
得到的类型是 Int32
。
于是我们可以得出结论:
- 对于可空值类型,当为
null
时,GetType()
会出现空引用异常; - 对于可空值类型,当不为
null
时,GetType()
返回的是对应的基础类型,而不是可空值类型; typeof(int?)
能够得到可空值类型。
Object.GetType() 和 is 对 Nullable 的作用
在 docs.microsoft.com 中,有一段对此的描述:
When you call the Object.GetType method on an instance of a nullable type, the instance is boxed to Object. As boxing of a non-null instance of a nullable type is equivalent to boxing of a value of the underlying type, GetType returns a Type object that represents the underlying type of a nullable type.
意思是说,当你对一个可空值类型 Nullable<T>
调用 Object.GetType()
方法的时候,这个实例会被装箱,会被隐式转换为一个 object
对象。然而对可空值类型的装箱与对值类型本身的装箱是同样的操作,所以调用 GetType()
的时候都是返回这个对象对应的实际基础类型。例如对一个 int?
进行装箱和对 int
装箱得到的 object
对象是一样的,于是 GetType()
实际上是不能区分这两种情况的。
那什么样的装箱会使得两个不同的类型被装箱为同一个了呢?
另一篇文档描述了 Nullable<T>
装箱的过程:
- If HasValue returns false, the null reference is produced.
- If HasValue returns true, a value of the underlying value type T is boxed, not the instance of Nullable.
- 如果
HasValue
返回false
,那么就装箱一个null
- 如果
HasValue
返回true
,那么就将Nullable<T>
中的T
进行装箱,而不是Nullable<T>
的实例。
这才是为什么 GetType()
会得到以上结果的原因。
同样的,也不能使用 is
运算符来确定这个类型到底是不是可空值类型:
Console.WriteLine($"value is int = {value is int}");
Console.WriteLine($"value is int? = {value is int?}");
最终得到两者都是 True
。
应该如何判断可空值类型的真实类型
使用 Nullable.GetUnderlyingType(type)
方法,能够得到一个可空值类型中的基础类型,也就是得到 Nullable<T>
中 T
的类型。如果得不到就返回 null
。
所以使用以下方法可以判断 type
的真实类型。
bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;
然而,这个 type
的实例怎么来呢?根据前面的示例代码,我们又不能调用 GetType()
方法。
实际上,这个 type
的实例就是拿不到,在运行时是不能确定的。我们只能在编译时确定,就像下面这样:
bool IsOfNullableType<T>(T _) => Nullable.GetUnderlyingType(typeof(T)) != null;
如果你是运行时拿到的可空值类型的实例,那么实际上此方法也是无能为力的。
public class Program
{
public static void Main(string[] args)
{
Console.Title = "walterlv's demo";
int? value = GetValue(1);
object o = value;
Console.WriteLine($"value is nullable? {IsOfNullableType(value)}");
Console.WriteLine($"o is nullable? {IsOfNullableType(o)}");
Console.ReadLine();
}
private static int? GetValue(int? source) => source;
static bool IsOfNullableType<T>(T _) => Nullable.GetUnderlyingType(typeof(T)) != null;
}
参考资料
- c# - Nullable type is not a nullable type? - Stack Overflow
- How to: Identify a nullable type - C# Programming Guide - Microsoft Docs
- Using nullable types - C# Programming Guide - Microsoft Docs
我的博客会首发于 https://walterlv.com/,而 CSDN 和博客园仅从其中摘选发布,而且一旦发布了就不再更新。
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://blog.csdn.net/wpwalter),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
int? 竟然真的可以是 null!.NET/C# 确定可空值类型 Nullable 实例的真实类型的更多相关文章
- int不可为null引发的 MyBatis做持久层框架,返回值类型要为Integer问题
MyBatis做持久层框架,返回值类型要为Integer MyBatis 做持久层时,之前没注意,有时候为了偷懒使用了int类型做为返回的类型,这样是不可取的,MyBatis做持久层框架,返回值类型要 ...
- 如果不空null并且不是空字符串才去修改这个值,但这样写只能针对字符串(String)类型,如果是Integer类型的话就会有问题了。 int i = 0; i!=''。 mybatis中会返回tr
mybatis 参数为Integer型数据并赋值0时,有这样一个问题: mybatis.xml中有if判断条件判断参数不为空时,赋值为0的Integer参数被mybatis判断为空,因此不执行< ...
- 工作总结 无法确定条件表达式的类型,因为“<null>”和“System.DateTime”之间没有隐式转换 解决办法 object——Nullable<T> (可空类型)
可空值类型 备注 一种类型认为是可以为 null,如果它可以分配一个值,也可以分配null,这意味着类型具有无论如何没有值. 默认情况下,所有都引用类型,如String,是否可以为 null, ...
- 2016年11月3日JS脚本简介数据类型: 1.整型:int 2.小数类型: float(单精度) double(双精度) decimal () 3.字符类型: chr 4.字符串类型:sting 5.日期时间:datetime 6.布尔型数据:bool 7.对象类型:object 8.二进制:binary 语言类型: 1.强类型语言:c++ c c# java 2.弱类型语
数据类型: 1.整型:int 2.小数类型: float(单精度) double(双精度) decimal () 3.字符类型: chr 4.字符串类型:sting 5.日期时间:datetime 6 ...
- 关于 JavaScript 的 null 和 undefined,判断 null 的真实类型
null.undefined 博客地址: https://ainyi.com/39 undefined:表示一个变量最原始的状态,而非人为操作的结果 null:表示一个对象被人为的重置为空对象,而非一 ...
- hdu_1014(竟然真的还有更水的)
注意输出就没了... #include<cstdio> #include<cstring> using namespace std; int gcd(int a, int b) ...
- 你真的知道typeof null的结果为什么是‘object‘吗?
到目前为止,ECMAScript 标准中定义了8种数据类型,它们分别是Undefined.Null.Number.Boolean.String.Symbol.BigInt.Object. 为了判断变量 ...
- Item 30 用enum代替int常量类型枚举,string常量类型枚举
1.用枚举类型替代int枚举类型和string枚举类型 public class Show { // Int枚举类型 // public static final int APPLE_FUJI ...
- null值可以赋给引用变量,不能给基本类型
下面正确的写法是? cbyte i=128 boolean i=null long i=0xfffL double i=0.9239d null表示没有地址:null可以赋值给引用变量,不能将null ...
随机推荐
- Shell循环输入符合条件为止
提供用户输入,直到输入d/D/r/R为止. #!/bin/bash ]; do echo -n "(D)ebug or (R)elease?" read select_build_ ...
- 免费下载知网文献的方法 | sci-hub免费下载SCI论文方法
部分方法参考自在家里如何免费使用中国知网? - 大学生 - 知乎的回答,已注明出处. 知网文献下载:idata中国知网 idata中国知网网址:idata中国知网 https://www.cn-ki. ...
- php--------php库生成二维码和有logo的二维码
php生成二维码和带有logo的二维码,上一篇博客讲的是js实现二维码:php--------使用js生成二维码. 今天写的这个小案例是使用php库生成二维码: 效果图: 使用了 php ...
- 『PyTorch』第十二弹_nn.Module和nn.functional
大部分nn中的层class都有nn.function对应,其区别是: nn.Module实现的layer是由class Layer(nn.Module)定义的特殊类,会自动提取可学习参数nn.Para ...
- 基于binlog的增量备份
1.1 增量备份简介 增量备份是指在一次全备份或上一次增量备份后,以后每次的备份只需备份与前一次相比增加或者被修改的文件.这就意味着,第一次增量备份的对象是进行全备后所产生的增加和修改的文件:第二次增 ...
- 在linux中,如何增加、修改、删除、暂停和冻结用户名
在Linux中,如何增加.修改.删除.暂停和冻结用户名 在操作增加.修改和删除用户名前,先认识linux中两个最重要的文件,它们就是账号管理最重要文件“/etc/passwd”与“etc/shadow ...
- 数据库故障诊断(Troubleshooting)之性能问题导致的数据库严重故障案例之一
好久不来这里写东西,今天有点时间,来这里写点最近遇到的事情.前段时间,某电信业务用户因某核心生产库最近多次宕机重启,多方人员介入无果后,给我发来了邮件,大概意思就是现在该问题已经造成了比较严重的后果, ...
- SQL TUNING——从近半小时到几十毫秒的一次优化
昨天,一个用户的现场人员打电话紧急求助,说他们的一个系统卡了,半天不出结果,严重的影响了他们的使用,我简单的问了几句:什么时候的事儿?答:就今天下午的事儿.问:数据库软硬件最近动过没?答:没动过.问: ...
- Mac下的nodeJs版本切换和升级
在我们开发多个项目的时候,因为框架支持的node版本不同,所以要切换多个node版本 首先我们要使用npm安装一个模块 n 的全局 1.npm install -g n 2.使用 n 加版本号就 ...
- vue input框数字后保留两位小数正则
<el-input type="text" v-model.trim="ruleForm2.marketPrice" maxlength="10 ...