匹夫细说C#:可以为null的值类型,详解可空值类型
标签:
首先祝大家中秋佳节快乐~ 0x00 前言众所周知的一点是C#语言是一种强调类型的语言,而C#作为Unity3D中的游戏脚本主流语言,在我们的开发工作中能够驾驭好它的这个特点便十分重要。事实上,怎么强调C#的这个特点都不为过,因为它牵涉到编程的很多方面。一个很好的例子便是我们本文要介绍的内容——可空型,它是因何出现的,而它的出现又有什么意义呢?以及如何在Unity3D游戏的开发中使用它呢?那么就请各位读者朋友带着这些疑问,通过下面的文字来寻找这些问题的答案吧。
0x01 如果没有值?一个了解一点C#基础知识的人都知道,值类型的变量永远不会为null,因为值类型的值是其本身。而对于一个引用类型的变量来说,它的值则是对一个对象的引用。那么空引用是表示一个值呢,还是表示没有值呢?如果表示没有值,那么没有值可以算是一种有效的值吗?如果我们根据相关标准中关于引用类型的定义,我们其实很容易就可以发现,一个非空的引用值事实上提供了访问一个对象的途径,而空引用(null)当然也表示一个值,只不过它是一个特殊的值,即意味着该变量没有引用任何对象。但null在本质上和其他的引用的处理方式是一样的,通过相同的方式在内存中存储,只不过内存会全部使用0来表示null,因为这种操作的开销最低,仅仅需要将一块内存清除,这也是为何所有的引用类型的实例默认值都是null的原因。
但是,正如在本节一开始说的,值类型的值永远不能是null,但是在我们的开发工作中是否会恰巧遇到一个必须让值类型变量的值既不是负数也不是0,而是真正的不存在的情况呢?答案是是的,很常见。
一种最常见的情况是在设计数据库时,是允许将一列的数据类型定义为一个32位整数,同时映射到C#中的Int32这个数据类型。但是,数据库中的一列值中是存在为空的可能性的,换言之在该列的某一行上的有可能是没有任何值的,即不是0也不是负无穷,而是实实在在的空。这样会带来很多的隐患,也使得C#在处理数据库时变得十分困难,原因上文已经提到过了,在C#中无法将值类型表示为空。
当然还有很多种可能的情况,例如在开发手机游戏时需要通过移动手指来滑动选择一块区域内的游戏单位,一次拖动完成之后,显然应该将本次拖动的数据清空,以作为开始下一次拖动的开始条件,而往往这些拖动数据在Unity3D的脚本语言中都是作为值类型出现的,因而无法直接设为空,所以也会给开发带来些许不便。
那么如果没有一个可以让值类型直接表示空的方法出现,我们是否还有别的手段来实现类似的功能呢?下面我们就来聊聊如果没有可空类型,应该如何在逻辑上近似实现值类型表示空的功能。
0x02 表示空值的一些方案假设如果真的没有一种可以直接表示空值的方案出现,那么我们是否能想到一些替代方案呢?所以本节就归纳一下三种用来表示空值的方案。
1.使用魔值首先我们要知道值类型的值都是它本身,换言之每个值我们都希望是有意义的。而魔值这个概念或者说方案的出现,恰恰是违背这一原则的,即放弃一个有意义的值,并且使用它来表示空值,这个值在我们的逻辑中与别的值不同,这便是魔值。因为它让一个有意义的值消失了,例如魔值选为-1000,那么-1000这个值便不再表示-1000了,相反,它意味着空。
回到刚刚的例子中,在数据库中如果有映射成Int32类型的某列值中恰好有一个是空,那么我们可以选择(牺牲)一个恰当的值来表示空。这样做的好处在于不会浪费内存,同样也不需要定义新的类型。但牺牲哪个值来作为魔值便成为了一个需要慎重考虑的事情。因为一旦做出选择,就意味着一个有意义的值的消失。
当然,使用魔值这种方案在实际的开发中也显得很low,这是因为问题并没有被真正的解决,相反,我们只是耍了一个小聪明来实现暂时蒙混过关。因此我并不十分喜欢这种方案。
2 使用标志位如果我们不想浪费或者说牺牲掉一个有意义的值来让它作为魔值来表示空的话,那么只用一个值类型的实例是不够的。这时候我们能想到的一个解决方案就是使用额外的bool型变量作为一个标识,来判定对应的值类型实例是否是空值。这种方案具体操作起来有很多种方式,例如我们可以保留两个实例,一个是表示我们所需的普通的值的变量,另一个则是标识它是否为空值的bool类型的变量。如下面这段代码所示:
//使用bool型变量作为标识 using UnityEngine; using System; using System.Collections.Generic; public class Example : MonoBehaviour { private float _realValue; private bool _nullFlag; private void Update() { this._realValue = Time.time; this._nullFlag = false; this.PrintNum(this._realValue); } private void LateUpdate() { this._nullFlag = true; this.PrintNum(this._realValue); } // Use this for initialization private void Start () { } private void PrintNum(float number) { if(this._nullFlag) { Debug.Log("传入的数字为空值"); return; } Debug.Log("传入的数字为:" + number); } }
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/66996.html
- 上一篇:初测WIN10
- 下一篇:js文件处理 File API