• 欢迎访问我爱CSharp学习网,这里有最新最全的C#书籍,C#视频。
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏我爱C#学习网吧
  • 推荐使用最新版Chrome浏览器和火狐浏览器访问本网站

C#类型本质—进阶编程篇(一)

C#杂烩 52csharp 731次浏览 0个评论 扫描二维码

这是我的第一篇讲解编程技巧的教程文章,不管是措辞还是排版,肯定有诸多不完善的地方,还请各位多多担待。对于专业知识来说,因为技术是会存在过时的,所以我也没有办法保证所讲解的内容完全是正确的,而且我觉得我理解的还不够深,将来的某一天可能也会回头修正现在的表述,说明,也就是传说中的打脸,但是这件事情总是要有个开端的,既然想到这个问题,就何不从现在开始去做呢。


这个系列的文章在专业性方面,我会尽可能的讲解我清楚的,如果我自己也不清楚,我会参考一些书籍,如果还没有书籍参考,那我就通过自己的经验来做了,大体上我会为我的教程负责的,希望可以帮到目前正在编程或将要编程的你们,你们是最可爱的人。


下面进入正题,也就是进阶编程篇的第一篇,C#类型的本质,本来本章也想了另一个名称:你真的了解类型吗?后来觉得太装B了,所以仍然使用了C#本质的标题。要进入本片学习,我需要假定您已经看过基础的C#编程书了,至少会简单的拖控件开发了,可以显示显示的数据,也会自定义控件的开发。正式进入提高阶段,如果您没有基础的知识,推荐您去学习《C#从人们到精通》这本书了,OK,马上进入正题。


我们都知道日常使用的类型,比如byte,int,long,等,除了这些值类型之外,还有各种库提供的类和我们自己开发的类。比如

Timer time1=new Timer();

我们非常习惯使用这些类型来创建示例,并且使用的很自然,比如

int i = 0;


OK,那我们来讲解第一个问题,不知道你有没有发现,在visual studio开发程序的时候,对于我们熟悉的int类型,IDE提供了两套类型模式,比如int和Int32,根据查看MSDN的说法,两者是一致的,如果真的是一致的,又为什么提供两种命名方式呢,这个问题的解释有点复杂,关系到程序运行的机制,而C#只是一种语言,一种编写CLR程序的语言,VS将我们用C#编写的程序翻译成了IL中间语言的程序,因为CLR和IL语言是无缝集成的,这样我们的程序才可以在CLR上运行,可能有些人会疑问,我们写的程序不应该是windows来运行的吗,本质上确实是如此,由windows来运行CLR,CLR来运行托管程序。那么问题来了,IL中间语言本身就直接支持了一套类型,比如Int32,Int16,Int64,等等,这套类型叫做基元类型,在微软开发C#编译器的时候,脑子一热,觉得原来的名称不太符合C语言的习惯,所以就额外提供了一套新的类型命名,int,short,long等,在编译的时候直接会编译成CLR支持的类型,至于在使用习惯上,根据自己的习惯选择,有些书会比较推荐CLR的标准。


第二个有意思的问题是如果我写了个静态的int变量,就可以在程序的任何地方(可以在不同的线程)进行引用,获取,设置值而不用担心其他问题,比如竞争问题。不要思考也还好,一旦要去考虑这个问题的答案,背后就隐藏了一个极大的秘密,对象数据的本质。我们在实例化一个对象后,如下

int i=0;

这行代码不仅仅只是生成了一个4个字节的变量数据,准确的说,对象i的数据部分确实是4个字节而已,但是对象本身绝对不是4个字节的问题,它还有另外两个非常重要的数据对象,叫同步索引块和类型对象块,而其中的同步索引块就控制了类型在同一瞬间只能进行一次设置,我们知道数据都是01组成,我们在执行i=0xffffff时,在另一个地方刚好获取i的值,这样就避免了万一设置到一半(i=0xff0000),我们就获取到了错误的值的可能性。


第三个有意思的问题是对象其实知道它自己的类型,还是拿上述的

int i=0;

作为说明对象,我们可以调用i.GetType()来获取i本身的类型,你可能会觉得这玩意到底有什么用,我自己定义的i我还不知道他是什么类型吗?

事实上用处大了,我先说明有什么用处,在说明原因。正是因为对象自己知道自己的类型,才能执行一些类型的转换,强制转换也好,隐式转换也罢,C#所有的转换建立在这个基础之上的,再看下面的代码:

int i=0;

object obj=(object)i;

string m=(string)obj;

在第二行代码中,因为编译器知道object是所有类的基类,所以可以转化,但是obj对象的类型真的是object吗?答案是不一定的,因为object是所有类的基类,所以obj理论上来说可以是任何类型,此处你可以获取类型来确认,obj其实是int类型。正是因为int类型和string类型不存在继承关系,所以第三行代码报错。


第四个有意思的问题是,我们都知道int使用了四个字节,byte使用了一个字节,但是如果我问bool使用了几个字节?还是一个位而已?这个问题就需要实践出真知了,我们就写代码来判断吧,声明一个类

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]

    public class SomeValType

    {

        [System.Runtime.InteropServices.FieldOffset(0)]

        public byte ValueByte = 0;

        [System.Runtime.InteropServices.FieldOffset(0)]

        public int ValueInt = 0;

        [System.Runtime.InteropServices.FieldOffset(0)]

        public bool ValueBool = false;

    } 

然后在其他地方使用断点查看,代码如下:

SomeValType value = new SomeValType();

            value.ValueInt = -1;

            value.ValueBool = false;

这时候监视查看到bool对象只影响了一个字节。这种技术允许数据区域重叠,你改变一个变量的时候也会影响其他变量,有些情况会比较适合,比如是一个IP类型,由四个字节组成,一个int就能表示,但也允许设置单个的网段。


第五个有意思的类型就是string了,看似平凡的字符串,背后的东西多的不得了,字符串类型有个非常大的特性,它是不易变的。如果你定义了一个字符串string m=”123456″;,它就傻傻的呆在一个内存块中,不会变化,直到被清除为止,所以针对如下代码怎么去理解:

string s = “”;

            for (int i = 0; i < 10000; i++)

            {

                s += “1”;

            }

s的最终结果是10000个1组成的字符串,但是中间有一万次的重新分配和删除,实际的性能非常差,应该避免这种情况。

关于string类型最难的就是本地化了,虽然大多数的程序员都不太关心这个问题,因为大多数的程序都只是给一个特定语言使用的,比如说中文,比如说英文,所以此处就简单的提个例子,即时两个看着不同的string,因为语言文化不一致,在比较相同的时候也是可能相同的。


第一篇文章就大致写到这里,以后有机会再补充。




我爱CSharp学习网 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C#类型本质—进阶编程篇(一)
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址