这个星期开始了
.NET FRAMEWORK
的学习,跟
C#
的基础学习有些不同,这
5
天的学习都是一些比较高级的应用,所以比基础知识难掌握一些,但是相应的,应用熟练后对自己的提升也是很大的。
第一天
首先学了
.NET FRAMEWORK
的基础知识,
.NET FRAMEWORK
的基础是公共语言运行库,虽然公共语言运行库的功能很多,但是最基本的原则是代码管理,以运行库为目标的代码称为托管代码,托管代码拥有以下特性:
1
跨语言集成
2
跨语言异处理
3
增强的安全性版本
4
控制部署
5
支持简化的组件交互
6
模型调试和分析服务。而是否是托管代码直接影响将来是否能用反射这个类找出源代码。
.NET FRAMEWORK
另一个重要组件是类库,利用类库可以方便的做出各种应用程序,是一个综合性的面向对象的可重用类型集合,而我现在对类库的理解还很粗浅,或者说接触的不够多,需要磨练。
之后又学到
.NET FRAMEWORK
的垃圾回收机制,传统的语言如
C++
,需要自己指定内存大小,分配内存,自己分配的内存肯定会存在大小差异,多个对象的情况下就会产生很多碎片,是对系统资源的浪费。而
C#
做出了很大的优化,实例化的时候,首先由系统计算字段所需的空间,对于对象所需的空间,
.NET FRAMEWORK
用两部分来处理:
1
同步块索引
2
类型对象指针。系统用事先计算好的空间来分配物理内存,然后新对象指针指到下一个可用区域,这样就使得内存的利用率十分高,减少碎片的产生,而且在垃圾回收的时候好做处理,回收首先是――标记阶段,即从根标记遍历到的对象,之后是压缩阶段,释放没有遍历到的对象,同时把后面的对象都向前压缩,新对象指针也跟着压缩,指向下一个可用区域。
这里又不得不提到
CLR
的垃圾收集器中很重要的一个概念:代(
Generation
)
,代的目的是提高应用程序性能。托管堆中的对象分为
3
代,其中第
0
代对象的生存周期最短,第
2
代的生存周期越长。所以
3
代的预算容量分别为
256K, 2M
,
10M
。当第
0
代的预算容量满了的时候,垃圾收集器开始工作,释放不需要的对象,同时仍然需要的对象就放到第
1
代,当
1
代也满了的时候,
1
代仍然需要的对象就成为了第
2
代。这种处理极大的提高了性能。
基础概念差不多就这样,然后学习的第一个
.NET FRAMEWORK
的类是文件和流的类,
directory
,
file
和
stream
。
File
没什么好说的,基本上就是对文本文件的操作。而
directory
类的说法就比较多了,之前做了个控制台的资源管理器,就得用到
directory
的各种类,将来无论
C/S
还是
B/S
都不会少了它。而
stream
,我觉得很重要。流是字节序列的抽象概念,例如文件、输入
/
输出设备、内部进程通信管道或者
TCP/IP
套接字。掌握好流的应用是十分重要的,而流又分为
3
个基本操作,读,写,查找。虽然重要,但是并不是理解性的东西,记住格式即可
。
第一天的东西基本就这么多,把
.NET FRAMEWORK
庞大的世界打开了一个门缝。
第二天
今天主要讲了两方面的内容:
1
多线程 2
网络编程
首先来说说多线程,在学
C#
的时候,老桂让做过一个钟表的程序,附加有秒表,闹钟的功能。这个程序就必须用到多线程的知识,不过那时候还没有学,做起来很吃力,现在来看的话就能轻松完成了。每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构。所以说线程都是单独的,线程是分配处理器时间的基本单元。在同一个时间片只能有一个线程运行,其他的都是挂起状态。所以
CPU
繁忙的情况下,线程优先级的设置就对线程的执行起到很大的作用,上课的例子是兔子赛跑,在
CPU
繁忙的情况下,优先级最高的线程第一个跑完。而在
CPU
空闲的状态,
3
个优先级几乎是同一时间完成的。
线程的定义过程如下:首先定义线程的
threadstart
,用来表示在线程中执行的方法,然后定义一个
thread
,需要的参数为
threadstart
,之后就可以
thread.start
()了。
Abort
为中止线程执行。
Sleep
使线程睡眠一段时间,方法的参数为睡眠的毫秒数。其中
sleep
的使用次数是挺多的。需要注意的一个方法是
lock
,用来阻止共享资源被多个线程同时操作而造成的错误,
lock
类似于对象锁,不够正牌的对象锁是
monitor
,
Monitor
类
通过向单个线程授予对象锁来控制对对象的访问。
小知识:
lock
所用的卖书的范例即是典型的消费者和生产者模式。生产几本,就只能卖几本。
接下来就讲到了
TCP/IP
协议。
总体来说,在
.NET
用到的底层网络方面的知识不多,只要会用套接字就可以了。
1
需要建立一个
ipaddress
,这个
IP
地址必须是本机地址,因为
framework
只提供自己电脑的端口监听,不允许黑客行为。
2
,建立一个监听
tcplistener
,参数为本机地址和端口号。
3
,因为
TCP
为安全连接,所以也需要建立客户端的对象
tcpclient
,用于获取监听到的
client
。
4
,用网络流
netstream
获得客户端发来的流。发送或者接收都通过流的形式。不过发送的时候需要将信息转化为
byte
的数组。用
byte
方法。
后来讲了服务器一对多客户端,又分为长连接和短连接,长连接就需要每次
new
一个监听的时候都新建一个线程,短连接则不需要。
Framework
几乎封装了所有底层的东西,对网络完全不了解也可以使用套接字。至于之后讲的
UDP
,因为通讯不需要握手,实现起来也相对简单。
多线程是很重要的知识点,以后做项目的时候肯定是离不开的,网络这块,做
B/S
的话,基本上就用不到。但是也得掌握。
第三天
今天的知识点是正则表达式和泛型。
首先说正则表达式,正则十分简练,十分强大,以至于完全理解正则很难,能做到日常应用即可。。
泛型以前接触过
list
类,现在学的主要就是如何自定义泛型类
class Demo<T>
{
T t;
public T T1
{
get { return t; }
set { t = value; }
}
}
这样子,一个简单的泛型类就建立起来了,
T
可以传进任意类型。一般情况下,创建泛型类的过程为:从一个现有的具体类开始,逐一将每个类型更改为类型参数,直至达到通用化和可用性的最佳平衡。
基本上泛型和正则就这样了。。
第四天
今天才是重头戏,主要的知识点有反射,特性,序列化。
先说反射,用
framework
的反射,就不得不说到
.NET
程序的运行过程。其实所有程序都是经过两次编译一次执行。源代码经过编译器的第一次编译,形成了
IL
元数据,在经过
CLR JLT
的第二次编译,才转化为机器识别的代码,最后代码被执行。
每个托管模块都包含元数据表。包括两种表:一是类型的表描述源代码中定义的类型和成员,另一种类型的表描述源代码引用的类型和成员。
知道了元数据之后,反过来看反射,反射是编程的读取与类型相关联的元数据的行为。通读取元数据,可以了解它是什么类型以及类型的成员。比如类中的属性,方法,事件等。通过这种方式,可以获得一个已经封装好的
DLL
或者
EXE
程序里面的代码。当然前提是这个可执行程序必须含有。
NET
可识别托管模块。根据
MSDN
的解释,这种反射并非是
.NET
的弊端,而是语言的特性,并且可以通过混淆器手动的使反射失败。混淆器则是反射的天敌,混淆过的代码即使反射出来,也是一堆混乱并且难以理解的代码。而在程序中,用反射类对混淆过的程序进行反射只会返回一条语句,说明该文件已混淆。
反射很强大,尤其是结合了特性,序列化之后,会有很厉害的应用。
现在再说特性,
属性以两种形式出现:
- 一种是在公共语言运行库 (CLR) 中定义的属性。
- 另一种是可以创建的用于向代码中添加附加信息的自定义属性。此信息可在以后以编程方式检索。
属性具有以下特点:
- 属性可向程序中添加元数据。元数据是嵌入程序中的信息,如编译器指令或数据描述。
- 程序可以使用反射检查自己的元数据。
- 通常使用属性与 COM 交互。
掌握了属性后,结合反射,功能就十分强大了,老桂的例子是用几个类,添加了属性后,结合反射做了个数据库语句的生成程序,很奇异。
最后再说说序列化。
可以将序列化定义为一个将对象状态存储到存储介质的过程。在这个过程中,对象的公共字段和私有字段以及类(包括含有该类的程序集)的名称,将转换成字节流,而字节流接着将写入数据流。随后对该对象进行反序列化时,将创建原始对象的准确克隆。
序列化的关键字在于:对象状态,转成字节流
byte
。
第一次用的时候,把字段定义成静态的,结果发现序列化中找不到,仔细想了想,静态字段是属于类的,而不是属于可实例化的对象,所以序列化不到。这是个需要注意的地方。
序列化对象需要在对象前加上
[Serializable]
,没有这个特性的对象不会被序列化。而微软自己封装好的类,想序列化怎么做呢?继承下来,加上
[Serializable]
就可以了。。当然父类不能序列化的对象在子类里定义成序列化的是会出问题的。这时候就得用到以下的构造函数和虚方法
public class Person
{
public bool sex;
}
[Serializable]
public class Chinese : Person,ISerializable
{
public string complexion;
public Chinese()
{ }
public Chinese(SerializationInfo info, StreamingContext context)
{
sex = info.GetBoolean("sex");
complexion = info.GetString("complexion");
}
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("sex", sex);
info.AddValue("complexion", complexion);
}
}
大概的知识点就这么多,当然还遗漏了很多,慢慢在实际中体会吧