C#的变迁史01 - C# 1.0篇

      C#与.NET平台诞生已有10数年了,在每次重大的版本升级中,微软都为这门年轻的语言添加了许多实用的特性,下面我们就来看看每个版本都有些什么。老实说,分清这些并没什么太大的实际意义,但是很多老资格的.NET程序员还是热衷在面试中咬文嚼字,所以茶余饭后了解一下也是不错的,所说的内容是对还是错,大家还是勤搜搜看,有误导的地方的还请见谅。

      第一代C#只是具有了面向对象语言该有的大框架。这些元素,基本上是每种现代化面向对象语言都有的。
1. 面向对象的基本特征 - 继承,封装,多态

      我相信任何一门现代化的面向对象的语言必然实现这些机制,这些东东必然是不可缺少的,这是面向对象编程的核心:继承机制复用了代码,多态机制表征了变化,封装机制隐藏了细节。

      也许JavaScript的同仁们不太同意这个说法,确实是,以函数为第一类成员的JS确实淡化了类,没有了接口的概念,但是以Object作为单一根,原型链实现的对象的继承,还是隐约可以看到面向对象的特质。

      在C#的实现中,本质上是函数,使用时却像是字段一样的Property比较特别,个人觉得这种设计使用上相当的方便。当然了,有些莫名其妙的面试者总是问C#中Attribute与Property有什么不同?我实在想问一下兄弟们:难道就因为这两个概念翻译过来都可以叫做"属性",就能生搬硬套搞出个辨析题?

2. 基本数据类型,值类型与引用类型

      对于常用的的操作数,C#也提供了基本的数据类型:int, double, bool, byte...。这些类型由于使用的太多,而且特性简单,创建和销毁比较容易,于是被设计成值类型(值拷贝,不允许继承)。除了这几种类型,其他的所有类型,包括自定义的类,接口,集合等出于传递性能等因素都被设计成引用类型(地址拷贝)。

      把一个类型设计成值类型,还是引用类型,这是一个问题。

      C++把所有类型设计成了值类型,于是不得不引入引用的概念,来优化内存和传参时的效率问题。据称,Java把所有的类型设计成引用类型,也是带来显著的性能问题。到了C#的时候,分类处理了一下,既有使用最密集的值类型,也有扩展性最好的引用类型。

      值类型是在定义的地方分配的,要么是线程堆栈上(函数参数),要么是托管堆上(作为引用类型的成员),引用类型只会在托管堆上分配。值类型传递的是拷贝,引用类型传递地址,这在传参时最为明显,传进来的值类型对象修改其值后并不会影响传经来之前的值,而引用类型传进来后,修改其值就是修改传进来之前的值,这个特点导致了很多隐藏的问题。当然值类型也可以传递地址给被调用的函数,这样修改传进来的值就是修改原来的值,这就是参数列表中ref与out关键字的作用,这个关键字显然对引用类型没什么效果。

      分类处理想法很好,却带来了的一定的复杂行,作为.NET单一根的Object类是一个引用类型,而子类却有一部分是值类型,于是为了满足面向对象"使用基类的地方也可以使用子类"的约定,需要在需要Object类型的时候把值类型包装一下,添加上该有的一些指针,变成引用类型传出去,这就是装箱,在真正使用的时候再把值拷贝出来转成值类型,这是拆箱,在没有泛型之前,这种效率损失有时真的难以让人忍受,特别是某些效率至上的同仁。

      说到效率,就不得不说说特殊的string类型,这种类型的使用范围很广,C#的根类Object都提供了ToString方法。从用户角度来说,任何的输出和输入都是字符串,这是字符串受到重视的原因。但是字符串的特性、实现与运算比较复杂,被设计成引用类型。string类的使用方式也是严重影响效率的一个方面。string类实现了字符串的恒定性,而且使用了驻留机制,任何字符串修改操作都是生成新的字符串,这使得如果高频率的使用字符串的修改方法(例如大规模的循环)时,内存会表示压力很大。StringBuilder恰到好处的解决了这些问题,因而成为了string类使用者的贴心伴侣。

      此外,深拷贝与浅拷贝也是很常见的一个问题。深拷贝是把对象的所有数据全部拷贝一份,包括对象的成员指向的其他的对象也如此拷贝。而浅拷贝只是把当前对象的所有成员拷贝一份,如果该对象有成员指向别的对象,就不管了。

      毫无疑问,所有值类型实现的是深拷贝,因为它们没有指针指向别的地方,拷贝的时候就是把自己复制一份出来。

      引用类型就复杂了,因为引用类型内部的成员可能是引用类型,它会指向了别的内存空间。如果实现浅拷贝,那么引用类型的复制品中的引用成员还是与源对象一样,会指向同一个内存空间。如果实现深拷贝,那么被引用的内存空间也会复制一份,拷贝得到的新对象的成员会指向这个新的内存空间。

      C#中ICloneable接口提供了拷贝接口,需要实现这个功能的类需要自己实现浅拷贝或者深拷贝。此外,C#中基类Object中提供了浅拷贝的实现,所以自己的类中实现浅拷贝的方法最简单的就是调用Object的MemberwiseClone方法。注意C#中不指定基类的类默认都是从Object继承的。实现深拷贝就需要自己去复制和创建新的成员对象了,当然借助序列化和反序列化也是一种实现深拷贝的方式,因为反序列化的时候会创建全新的对象和引用关系。

3. 集合

      语言是解决实际问题的,实际中有群体的概念,程序中自然就有集合的概念,这是类型系统中不可或缺的重量级成员。集合是第一版C#中装箱拆箱的重灾区,使用集合的时候到处充斥着难以忍受的类型装换以及性能损失。

      C#的常用集合如Array,ArrayList,Queue,Stack等等都是基于连续内存的一种实现,简单的说都是基于数组实现的,这个自然是访问性与插入删除这两种类型操作之间效率权衡的结果。当然了C#中也有像LinkedList这种链表类集合,实际使用中需要根据操作类型(读取为主?修改为主?)的频率选择合适的集合。

      与集合密切相关的是迭代器模式,集合负责保存元素,遍历和枚举的过程就交给了迭代器,这是符合面向对象设计中单一职责原则的。在C#中,如果想使用foreach这种迭代语法的时候,需要先检查一下你自定义的集合是否实现了IEnumerable接口,当然了,内置的集合全部是实现了该接口的。

4. 消息机制,事件与代理

      对象有了,那么下一步就是协同工作了。使用delegate定义回调函数的样式与使用event定义消息通知的接口构成了C#通信的基本基调:注册,通知,回调;这也是观察者模式的核心内容。

      作为安全的函数指针,delegate近乎完美的完成了自己的工作,但是使用起来需要采用new实例的方式去初始化,似乎不够方便,后面的版本中微软提供了更方便的实现方式。

5. 多线程(Thread方式)

      多线程与异步运行这是必须的,那么多的事情总不能一步接一步去做吧,有些事是没有严格的先后次序的,而且时间就是金钱啊,能省就省呗。

      内存的运行速度是杠杠的,那些外设的速度完全赶不上,但是基本上所有的程序都是要与外设打交道的,为了不浪费内存的时间,异步势在必行。原本来说,异步指的就是内存与外设不同步这个意思。

      同步执行大家都知道是程序一句接一句的执行,由于上面所说的异步是势在必行的,所以当编写程序的时候,为了不浪费内存的时间,有时候就需要异步的执行一些方法,这在C#中是允许的。

      在.NET类库中有很多异步调用的方法。一般都是已Begin开头End结尾构成一对异步委托方法,外加两个回调函数和AsyncState参数,组成异步操作的结构。异步编程,就是借助delegate,BeginInvoke,EndInvoke,AsyncCallBack,AsyncState,IAsycResult等类或方式来完成异步操作。

      多线程其实与异步没一毛钱关系,但是很多人习惯一起说,而且它们执行的方式有那么一点相同,那咱也一起说吧。多线程现在更多的是与多核联系在一起(单核的时候分时间片去运行不同的线程),既然咱不差钱,多买了几个核,不用总是浪费的,浪费可耻啊,那就用上,于是没有先后依赖关系的相对独立的一些任务就可以放到别的线程中做了,做好后以一定的方式(回调或者直接把结果塞回来)通知一下主线程就可以了。

      以Thread类为核心的一组类提供了基本的多线程功能,它们功能多样,用户可控性高(可以随时申请中止线程等操作),是许多多线程用户的最爱。同时,C#还有一个叫ThreadPool的玩意儿,用户只要塞给它一些活就不用管了,喝杯咖啡等待结果即可,十分方便,不喜欢操控性的用户很喜欢这种感觉。

 

      当然除了这些通用的元素,C#自身也存在很多闪光点:
1. Attribute特性

      这是C#特有的,其他语言还真没有这个东东。元数据是C#程序的重要信息,这些数据携带了一些信息,根据这些信息,负责解析的类或者框架可以完成一些很特别的功能。比如enum类型,当它带上Flag这顶帽子的时候,乖乖不得了了,它居然可以参与位运算了。一定程度上说,Attribute是一套强大的系统,一套强大的自定义系统。

2. 自动垃圾回收

      自动垃圾回收是通过GC这个类完成的,一般没什么人会去调用这个类的方法强制回收。自动垃圾回收以前可以要挂起相关线程,回收程序所有"根"没有引用的垃圾,压缩托管堆,重新修改引用的地址,然后再恢复现场的。效率应该不高,但是本人感受不深。据说现在可以回收的时候不挂起所有线程,不知道怎么样。

      垃圾回收与代龄的问题一般只是停留在讨论的层次,很少有人实际写程序中使用。但是与之相关的Dispose模式就风光了,如何实现一个标准的Dispose模式据说是很多Senior考生的必考项目。

      Dispose模式与using息息相关,using关键字后面的资源一定要实现IDisposible接口,这是using引用namespace之外的另一处用法,如何实现这个模式在网上一搜一大把,兄弟们自己看着办吧。

      此外,与垃圾回收息息相关的还有"~"方法,这个在C++中称为析构函数的家伙在C#一跃称为Finalize方法,标准的Dispose模式是包含这个函数处理的。实现了这个方法的类是需要二次回收的,第一次回收的时候这些对象托管资源释放以后,需要进行第二次回收,通常是回收非托管资源。处于两次回收之间的这些对象是可以复活的,但是实际中好像做的人不是太多。

3. 反射与动态创建

      动态创建时很酷的一个特性,很多语言比如Java中也有。通常是提供一个配置文件,XML可以,普通的TXT也可以,从里面读出一个字符串,然后从这个字符串变出一个类的实例然后使用,多炫啊。当然了反射不仅仅可以干这个,它还可以动态的加载一个dll,动态的创建类型,动态的调用类型的方法,这些都是字符串驱动的(参数都是字符串),是不是很帅?System.Activator,System.Reflection.Assembly,System.Type等是完成了这一特性的得力干将。

4. 中间语言的概念与CLR

      这两个家伙与自动垃圾回收是托管语言(微软提出来的概念,所以托管语言指的就是基于.NET的几种开发语言)的基石,他们彻底隔离了机器码与编程语言,于是C#,VB.NET,托管C++等编译后万祖归宗,编译后都变成了中间代码,等到第一次运行的时候,JIT编译器会将这些中间代码转换成真正的机器代码,这样据说很好的提供了程序的移植性。

      当然了为了提高程序启动的性能(总不能每次运行程序都需要JIT编译一下吧!),首次运行时JIT编译好的机器码会被秘密的保存在一个地方,这样下次运行程序的时候,就不需要JIT再次编译一下了。此外,很多高级玩家宣称:不懂中间语言IL,就不算真懂C#。对此,本人持保留态度,因为从我的角度来说,使用好语言才是目前的首要工作,刨根问底是以后的事,呵呵。

5. 统一而且完备的类库FCL

       提供一个完整的类库是相当有必要的,和以前的MFC是一个道理。使用一门语言时,比如JavaScript,每次当你看到多如牛毛的第三方插件和类库的时候,难道你没有想吐的欲望?这是微软相当具有竞争力的一个做法,不管你信不信,反正我信了。完备的FCL是支撑.NET大厦的砖头,没有这些东西,就没有.NET的各项功能,也就没有各位大佬们面试时拍人的武器了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

REVERSE-PRACTICE-BUUCTF-26

REVERSE-PRACTICE-BUUCTF-26[FlareOn6]FlareBear[SUCTF2018]babyre[GKCTF2020]WannaReverse[FlareOn4]greek_to_me[FlareOn6]FlareBear apk文件,模拟器上运行,创建一个小熊,有三种方式交互,分别为“吃饭”,“篮球”以…

C#的变迁史02 - C# 2.0篇

在此重申一下,本文仅代表个人观点,如有不妥之处,还请自己辨别。 第一代的值类型装箱与拆箱的效率极其低下,特别是在集合中的表现,所以第二代C#重点解决了装箱的问题,加入了泛型。1. 泛型 - 珍惜生命&#x…

REVERSE-PRACTICE-BUUCTF-27

REVERSE-PRACTICE-BUUCTF-27[XMAN2018排位赛]Dragon Quest[羊城杯 2020]easyre[watevrCTF 2019]Repyc[2019红帽杯]calc[XMAN2018排位赛]Dragon Quest elf文件,无壳,ida分析 main函数,读取输入,start_quest函数验证输入&#xff0…

C#的变迁史03 - C# 3.0篇

C# 3.0 (.NET 3.5, VS2008) 第三代C#在语法元素基本完备的基础上提供了全新的开发工具和集合数据查询方式,极大的方便了开发。 1. WPF,WCF,WF 这3个工程类型奠定了新一代.NET开发的客户端模型,通信模型,工作流模型。 …

REVERSE-PRACTICE-BUUCTF-28

REVERSE-PRACTICE-BUUCTF-28[FlareOn6]Memecat Battlestation[b01lers2020]chugga_chugga[INSHack2018]Tricky-Part1[watevrCTF 2019]esreveR[FlareOn6]Memecat Battlestation .Net程序,运行后输入weapon code,用dnSpy打开 在Stage1Form直接找到第一个w…

C#的变迁史04 - C# 4.0 之多线程篇

在.NET 4.0中,并行计算与多线程得到了一定程度的加强,这主要体现在并行对象Parallel,多线程Task,与PLinq。这里对这些相关的特性一起总结一下。 使用Thread方式的线程无疑是比较麻烦的,于是在这个版本中有了改善的版本…

REVERSE-PRACTICE-BUUCTF-29

REVERSE-PRACTICE-BUUCTF-29[FlareOn1]Shellolololol[CFI-CTF 2018]powerPacked[INSHack2018]Tricky-Part2[CFI-CTF 2018]Automated Reversing[FlareOn1]Shellolololol exe程序,直接不能运行,无壳,ida分析 简单F8单步调试发现,在…

C#的变迁史05 - C# 4.0篇

C# 4.0 (.NET 4.0, VS2010) 第四代C#借鉴了动态语言的特性,搞出了动态语言运行时,真的是全面向“高大上”靠齐啊。 1. DLR动态语言运行时 C#作为静态语言,它需要编译以后运行,在编译的过程中,编译器要检查语法的正确性…

REVERSE-PRACTICE-BUUCTF-30

REVERSE-PRACTICE-BUUCTF-30[RCTF2019]DontEatMe[b01lers2020]little_engine[NPUCTF2020]你好sao啊[MRCTF2020]Shit[RCTF2019]DontEatMe exe程序,运行后输入,无壳,用ida分析 交叉引用字符串来到sub_401260函数,读取输入&#xff…

C#的变迁史06 - C# 4.0 之并行处理篇

前面看完了Task对象,这里再看一下另一个息息相关的对象Parallel。 Parallel对象 Parallel对象封装了能够利用多核并行执行的多线程操作,其内部使用Task来分装多线程的任务并试图将它们分配到不同的内核中并行执行。请注意“试图”这个词,Par…

REVERSE-PRACTICE-BUUCTF-31

REVERSE-PRACTICE-BUUCTF-31[羊城杯 2020]login[羊城杯 2020]Bytecode[羊城杯 2020]babyre[ACTF新生赛2020]fungame[羊城杯 2020]login exe程序,运行后输入,无壳,ida分析 没找到主要逻辑,在字符串窗口看到一些“py”的字样&#…

C#的变迁史07 - C# 4.0 之线程安全集合篇

作为多线程和并行计算不得不考虑的问题就是临界资源的访问问题,解决临界资源的访问通常是加锁或者是使用信号量,这个大家应该很熟悉了。 而集合作为一种重要的临界资源,通用性更广,为了让大家更安全的使用它们,微软为我…

PWN-PRACTICE-BUUCTF-1

PWN-PRACTICE-BUUCTF-1test_your_ncripwarmup_csaw_2016ciscn_2019_n_1test_your_nc 附件的main函数直接system("/bin/sh"),nc直接连即可cat flag rip main函数中,gets函数读取一行会造成栈溢出 构造payload覆盖rip,使得return…

C#的变迁史08 - C# 5.0 之并行编程总结篇

C# 5.0 搭载于.NET 4.5和VS2012之上。 同步操作既简单又方便,我们平时都用它。但是对于某些情况,使用同步代码会严重影响程序的可响应性,通常来说就是影响程序性能。这些情况下,我们通常是采用异步编程来完成功能,这在…

REVERSE-PRACTICE-CTFSHOW-1

REVERSE-PRACTICE-CTFSHOW-1逆向签到题re2逆向4逆向5逆向签到题 ida打开即可得到明文flag re2 附件是一个加密过的flag文本和勒索病毒exe 运行程序,输入1,回车,直接退出,ida分析 选项1的逻辑为,打开flag.txt和enfl…

C#的变迁史09 - C# 5.0 之调用信息增强篇

Caller Information CallerInformation是一个简单的新特性,包括三个新引入的Attribute,使用它们可以用来获取方法调用者的信息, 这三个Attribute在System.Runtime.CompilerServices命名空间下,分别叫做CallerMemberNameAttribute&…

REVERSE-PRACTICE-CTFSHOW-2

REVERSE-PRACTICE-CTFSHOW-2re3红包题 武穆遗书数学不及格flag白给re3 main函数,分析可知,将输入的字符串按十六进制转成数字,写到v5,赋给v17[6] 当i等于6时,v16会加上输入的值,然后进入循环,最…

C#的变迁史10 - C# 5.0 之其他增强篇

1. 内置zip压缩与解压   Zip是最为常用的文件压缩格式之一,也被几乎所有操作系统支持。在之前,使用程序去进行zip压缩和解压要靠第三方组件去支持,这一点在.NET4.5中已有所改观,Zip压缩和解压功能已经内置于框架本身。这个功能使…

REVERSE-PRACTICE-CTFSHOW-3

REVERSE-PRACTICE-CTFSHOW-3签退神光签到baby_gay签退 .pyc文件,uncompyle6反编译,得到python源码,分析写在源码注释中 先变表base64,再凯撒加密,向后移动2位 import string c_charset string.ascii_uppercase str…

TFS多地办公时的处理

问题引出 我们在公司办公时使用的时公司内网,回家办公需要使用VPN远程拨号到服务器。这是,服务器的域名有可能发生变化,同时服务器的IP地址也发生了改变。故需要使用公司提供的swSVN工具,进行办公场所的切换 原因时:当…