当前位置: 首页 > 编程语言 > C#

装箱-拆箱可空类型-为什么要实现?分享

时间:2023-04-11 03:30:40 C#

装箱/拆箱可为null的类型-为什么要执行此操作?通过C#从CLR中提取关于装箱/拆箱值类型的信息...关于装箱:如果可为null的实例不为null,则CLR从可为null的实例中取出值并将其装箱。也就是说,一个值为5的Nullable被打包到一个值为5的boxed-Int32中。在拆箱中:拆箱只是获取对已装箱对象的未装箱部分的引用的行为。问题在于装箱值类型不能简单地拆箱为该值类型的可为空版本,因为装箱值中没有布尔hasValue字段。因此,当值类型拆箱为可空版本时,CLR必须分配一个Nullable对象,将hasValue字段初始化为true,并将值字段设置为装箱值类型中的相同值。这会影响您的应用程序性能(拆箱期间的内存分配)。为什么CLR团队要为Nullable类型经历这么多麻烦?为什么不首先将其设置为Nullable呢?我记得这种行为是最后一刻的改变。在.NET2.0的早期beta版本中,Nullable是一种“正常”值类型。装箱空值int?把它变成一个盒装的整数?带有布尔标志。我认为他们决定采用当前方法的原因是一致性。说:int?测试=空;对象obj=测试;if(test!=null)Console.WriteLine("testisnotnull");if(obj!=null)Console.WriteLine("obj不为空");在前一种方法中(boxnull->boxedNullable),你不会得到“testisnotnull”但是你得到“objectisnotnull”这很奇怪。另外,如果他们装箱为Nullable一个可为空的值:int?值=42;对象obj=val;if(obj!=null){//我们的对象不为空,所以直观上它是一个`int`值:intx=(int)obj;//...但这会失败。除此之外,我相信当前的行为对于像可空数据库值这样的场景非常有意义(想想SQL-CLR...)'具有有意义的价值。他们不想提供两种不同的类型。一个整数?应该表现得或多或少像一个简单的int。这就是C#提供提升运算符的原因。因此,当值类型拆箱为可空版本时,CLR必须分配一个Nullable对象,将hasValue字段初始化为true,并将值字段设置为装箱值类型中的相同值。这会影响您的应用程序性能(拆箱期间的内存分配)。这不是真的。CLR必须在堆栈上分配内存来保存变量,无论它是否可为空。为额外的布尔变量分配空间没有性能问题。我认为将空值设置为空引用是有意义的。有一个盒装值说“我知道如果我有一个值,我会是一个Int32,但我不是”对我来说似乎并不直观。最好从“非值”的值类型版本(HasValue为假的值)转换为“非值”的引用类型版本(空引用)。顺便说一句,我相信此更改是基于社区反馈。这也允许有趣地使用值类型:objectmightBeADouble=GetMyValue();双倍的?unboxed=mightBeADouble作为双倍?;if(unboxed!=null){...}这与使用引用类型处理“不确定转换”一样比以前更加一致:objectmightBeADouble=GetMyValue();如果(mightBeADouble是double){doubleunboxed=(double)mightBeADouble;...}(它也可能执行得更好,因为只有一个执行时间类型检查。)您通过这种行为获得的好处之一是盒装版本实现了底层类型支持的所有接口。(目的是为了所有实际目的使Nullable与int相同。)将Boxing-int装箱为boxed-Nullable而不是boxed-int可防止此行为。从MSDN页面,双?d=44.4;对象iBoxed=d;//访问double实现的IConvertible接口。IConvertibleic=(IConvertible)iBoxed;inti=ic.ToInt32(null);字符串str=ic.ToString();从Nullable的装箱版本中获取int也很简单——通常您不能将原始src类型以外的类型拆箱。浮动f=1.5f;对象boxed_float=f;intint_value=(int)boxed_float;//会爆炸。不能将float拆箱为int,您*必须*先将其拆箱为float。漂浮?nullableFloat=1.4f;boxed_float=nullableFloat;floatfValue=(float)boxed_float;//可以拆箱浮动吗?浮动Console.WriteLine(fValue);在这里,您不必知道原始版本是int还是Nullable。(+您还获得了一些性能;节省了在装箱对象中存储hasValue布尔值的空间)我想这基本上就是它的作用。给出的描述包括您的建议(即加载Nullable)。额外的是它在装箱后设置hasValue字段。我认为这种行为的原因源于Object.Equals的行为,最值得注意的是,如果第一个对象为null而第二个对象不是,则Object.Equals返回false而不是调用第二个对象上的Equals方法。如果Object.Equals在第一个对象为null而第二个对象不为null时调用第二个对象的Equals方法,则具有Nullable空值的对象在与null进行比较时可能会返回True。我个人认为正确的补救措施是让Nullable的HasValue属性独立于空引用的概念。关于在堆上存储布尔标志所涉及的开销,您可以提供每个类型Nullable的静态装箱空版本,然后提供未装箱的静态装箱空副本将产生一个空的Nullable,并且将任何其他实例拆箱填充的实例将是产生。这就是C#学习教程:装箱/拆箱可空类型-为什么要执行此操作?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: