随笔 - 136  文章 - 0  评论 - 36  阅读 - 17万 

随笔分类 -  Microsoft.Net框架程序设计学习笔记

异步编程模型APM(2)
摘要:使用APM执行受计算限制的异步操作 我们可以通过APM来调用任何方法,但首先,我们需要定义一个与我们希望调用的方法拥有相同签名的方法。以计算1至n间总和的方法为例(这是一个计算密集的任务,它不执行任何I/O操作)。private static UInt64 Sum(UInt64 n){ UInt64 sum = 0; for(UInt64 i = 1; i <= n; i++) { checked { //在此使用了checked代码,以便于当结果sum与类型UInt64不符时抛出一个异常 sum +... 阅读全文
posted @ 2011-11-05 19:37 辛勤的代码工 阅读(674) 评论(0) 推荐(0) 编辑
异步编程模型APM(1)
摘要:简介 执行异步操作是构建高性能、可扩展应用程序的关键,它允许我们能够用非常少的线各执行许多操作。MS CLR团队设计了一种模式,可以让开发人员方便地利用这种能力,这种模式称为异步编程模式(APM)。 在FCL中许多类型都支持APM,如下面一些具体例子:所有派生自System.IO.Stream并与硬件设计通信的类都提供了BeginRead和BeginWrite方法。System.Net.Dns类提供了BeginGetHostAddresses、BeginGetHostByName、BeginGetHostEntry和BeginResolve方法。所有派生自System.Net.WebReq.. 阅读全文
posted @ 2011-11-05 18:52 辛勤的代码工 阅读(1318) 评论(0) 推荐(0) 编辑
Timer类
摘要:定期执行受计算限制的异步操作 System.Threading命名空间中定义了一个Timer类,可使用这个类让CLR定期地调用方法。构建Timer类的实例时,实际是在告诉CLR我们希望一个方法在指定的时间内被再次调用。Timer类提供了几个非常相似的构造器:public sealed class Timer : MarshalByRefObject, IDisposable{ public Timer(TimerCallback callback, Object state, int dueTime, int period); public Timer(TimerCallback callba 阅读全文
posted @ 2011-07-10 23:42 辛勤的代码工 阅读(950) 评论(0) 推荐(0) 编辑
使用线程池与专用线程
摘要:高效线程使用圣典 严格来讲,线程的系统开销很大。系统必须为线程分配并初始化一个线程内核对象,还必须为每个线程保留1MB的地址空间(按需提交)用于线程的用户模式堆栈,分配12KB左右的地址空间用于线程的内核模式堆栈。然后,紧接着线程创建后,Windows调用进程中每个DLL都有的一个函数来通知进程中所有的DLL操作系统创建了一个新的线程。同样,销毁一个线程的开销也不小:进程中的每个DLL都要接收一个关于线程即将“死亡”的通知,而且内核对象及堆栈还需释放。 如果一台计算机中只有一个CPU,那么在某一时刻只有一个线程可以运行。Windows必须跟踪记录线程对象,而且是不停地跟踪记录每个线程对象。Wi 阅读全文
posted @ 2011-07-10 22:18 辛勤的代码工 阅读(868) 评论(0) 推荐(0) 编辑
可空类型
摘要:为理解可空类型是如何工作的,我们来看一看System.Nullable<T>类,它是在FCL中定义的。[Serializable, StructLayout(LayoutKind.Sequential)]public struct Nullable<T> where T : struct{ //这两个字段表示状态 private Boolean hasValue = false; //假定null internal T value = default(T); //假定所有比特都是零 public Nullable(T value) { this.value = valu 阅读全文
posted @ 2011-06-25 18:30 辛勤的代码工 阅读(746) 评论(1) 推荐(0) 编辑
泛型类型
摘要:“泛型”(generic)是公共语言运行库(CLR)和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”。 大多数算法都封装在一个类型中,CLR允许创建泛型引用类型和泛型值类型,但不允许创建泛型枚举类型。此外,CLR还允许创建泛型接口和泛型委托。少数情况下,一个方法可能封装了一个有用的算法,所以CLR允许创建一个引用类型、值类型或接口中定义的泛型方法。 泛型为开发人员提供了以下优势: 1. 源代码保护:使用一个泛型算法的开发人员不需要访问算法的源代码。 2. 类型安全性:将一个泛型算法应用于一个特定的类型时,编译器和CLR能理解开发人员的意图,并保证只有与指定数据类型兼容. 阅读全文
posted @ 2011-06-21 23:55 辛勤的代码工 阅读(2252) 评论(0) 推荐(0) 编辑
CLR的整个类型对象及其工作方法
摘要:下图展示了CLR加载一个进程,在这个进程中,可能存在多个线程。当一个线程创建时,它会分配到一个1MB大小的堆栈,这个堆栈空间用于向方法传递实参,并用于存储在方法内部定义的局部变量。堆栈是从高位内存发址向低位内存地址构建的。在图中,线程执行了一些代码,它的堆栈上已有一些数据。 在一个最基本的方法中,应该包含一些“开场白(prologue)”代码,它们负责在方法开始做它的工作前对其进行初始化。另外,还应包含一些“收场白(epilo-gue)"代码,它们负责在方法完成工作后对其进行清理,以返回调用者。现在,假定线程执行的代码要调用M1方法。当该方法始执行时,它的“开场白”代码从线程的堆栈中 阅读全文
posted @ 2011-06-19 22:45 辛勤的代码工 阅读(1093) 评论(1) 推荐(1) 编辑
Microsoft.Net框架程序设计学习笔记(39):反射
摘要:先绑定类型,然后调用方法的方式通常称为晚绑定。而早绑定指一个应用程序使用的类型和方法在编译时就已确定。 System.Reflection.Assembly类型提供了三个静态方法允许我们显式加裁一个程序集:Load(通过接受一个程序集标识来加载程序集,可加载弱程序集和强程序集)、LoadFrom(通过接受一个程序集文件完整路径名称加载程序集,仅能加载弱程序集)、LoadWithPartialName。我们应该尽可能使用Load方法,避免使用LoadFrom、LoadWithPartialName。 System.AppDomain也提供一个Load方法,该方法是一个实例方法,允许我们将一个程. 阅读全文
posted @ 2011-04-01 21:56 辛勤的代码工 阅读(394) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(38):CLR寄宿和应用程序域
摘要:CLR寄宿 开发CLR时,微软实际上是将其作为一个COM服务器实现在了一个DLL内。也就是说,微软为CLR定义了一个标准的COM接口,并且为该接口和COM服务器分配了GUID。我们安装.NET框架时,表CLR的COM服务器就像其他的COM服务器一样被注册到了Windows的注册表里。 任何Windows应用程序都可以寄宿CLR。我们的非托管宿主(如Windows PE文件格式,其或为一个Windows Exe文件,或为一个动态连接库DLL文件)可以调用CorBindToRuntimeEx函数(其原型定义在MSCorEE.h中)。CorBindToRuntimeEx函数实现在MSCorEE.dl 阅读全文
posted @ 2011-04-01 13:23 辛勤的代码工 阅读(467) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(37):对象的代龄
摘要:利用对象代龄提高垃圾收集效率 代龄是旨在提高垃圾收集器性能的一种机制。一个基于代龄的垃圾收集器有以下几点假设:对象越新,其生存期越短。对象越老,其生存期越长。对托管堆的一部分执行垃圾收集要比对整个托管堆执行垃圾收集速度更快。 CLR将对象代龄分为0、1、2,共三代,且对每一代的对象所占用内存容量都设定了一个阀值,代龄越大,内存容量阀值也越大。代龄对象所占用内存超出阀值时,将引发垃圾收集。 在托管堆初始化时,其中不包括任何对象。这时添加到托管堆中的对象被称为第0代对象。当第0代对象所占用内存超过了阀值时,垃圾收集器就必须启动了。经过垃圾收集后存活下来的对象被认为是第1代对象,同时第0代对象暂时空 阅读全文
posted @ 2011-03-31 21:52 辛勤的代码工 阅读(343) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(36):弱引用
摘要:假设有这样一些数据结构,它们很容易创建但却需要大量的内存和时间。如:我们需要知道用户硬盘中所有目录和文件,我们可以很容易构造一个树来反映这些信息,当应用程序运行时,它可以引用内存中的树,而不必再访问用户的硬盘。这样显然会极大提高应用程序的性能。 但问题在于这个树可能会非常庞大,需要许多内存。如果用户转而访问应用程序的其余部分,那么这个树可能变得不再必要,却浪费着许多内存。我们可能会放弃这个树的根对象的引用,但如果用户又切换回应用程序的第一部分,那我们又需要重新构造该树。使用弱引用,我们可以方便、高效的处理这种情况。 弱引用对象是这样一种对象,如果我们放弃该对象的强引用,将其转至弱引用时,它允. 阅读全文
posted @ 2011-03-31 17:46 辛勤的代码工 阅读(271) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(35):Dispose模式
摘要:Finalize方法的问题:不能确定它会在何时被调用。由于它不是一个公有方法,我们不能显式调用它。 要提供显式释放或关闭对象的能力,一个类型通常要实现一种被称为Dispose的模式。所有定义了Finalize方法的类型都应该实现本节所描述的Dispose模式以给用户更多的控制权。 上节中OSHandle类实现的改进版,使用Dispose模式:using System;using System.Collections.Generic;using System.Text;using System.Runtime.InteropServices;namespace DisposeTest{ pub. 阅读全文
posted @ 2011-03-31 16:59 辛勤的代码工 阅读(384) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(34):终止化操作
摘要:终止化操作 任何封装了非托管资源的类型,如文件、网络连接、套接字等,都必须支持一种称作终止化的操作。终止化操作允许一种资源在它所占用的内存被回收之前执行一些清理工作。要提供终止化操作,我们必须为类型重写一个名为Finalize的方法,该方法在Object中被定义为受保护的虚方法。当垃圾收集器判定一个对象为可收集的垃圾时,它便会调用该对象的Finalize方法。Finalize方法的实现通常便是调用CloseHandle函数。 然而,在C#中实现Finalize方法并非直接重写Finalize方法,C#编译器为我们提供了与C++析构函数类似特殊语法来定义Finalize方法。下例演示了如何定义一 阅读全文
posted @ 2011-03-30 23:20 辛勤的代码工 阅读(366) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(33):垃圾收集算法
摘要:每个.Net应用程序都有一组根(root)。一个根是一个存储位置,其中包含着一个指向引用类型的内存指针。该指针或指向一个托管堆中的对象,或被设为null。例如,所有的全局引用类型变量或静态引用类型变量都被认为是根。另外,一个线程堆栈上所有引用类型的本地变量或参数变量也被认为是一个根。最后,在一个方法内,指向引用类型对象的CPU寄存器也是一个根。 当JIT编译器编译一个方法的IL代码时,除了产生本地CPU代码外,JIT编译器还创建一个内部的表。该表中的每一个条目都标识着一个方法的本地CPU指令的字节偏移范围,以及该范围中一组包含根的内存地址(或CPU寄存器)。如下图: 如果在0x0000002. 阅读全文
posted @ 2011-03-30 21:30 辛勤的代码工 阅读(326) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(32):垃圾收集平台基本原理解析
摘要:创建、访问、释放资源的几个步骤:调用中间语言(IL)中的newobj指令,为表示某个特定资源的类型实例分配一定的内存空间。调用new操作符时,编译器产生newobj指令。初始化上一步所得的内存,设置资源的初始状态,使其可以为程序所用。类型实例构造器完成这类工作。通过访问类型成员来使用资源。销毁资源状态,执行清理工作。释放内存。引用类型所占的内存由垃圾收集器全权负责释放。值类型所占的内存将随着堆栈空间的消亡而自动消失,无所谓回收。 垃圾收集器对内存中的类型表示着何种资源一无所知,所以垃圾收集器并不清楚怎样执行上述步骤中的第4步。为使资源得到正确清理,开发人员必须自己编写这部分工作的代码。这些代码 阅读全文
posted @ 2011-03-30 20:43 辛勤的代码工 阅读(311) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(31):异常捕获、未处理异常、堆栈踪迹
摘要:异常捕获 异常捕获筛选器会判断抛出的异常类型是否和筛选器指定的类型相匹配,如果匹配成功,那么它会返回一个特殊的值通知CLR。CLR首先执行更低层次的堆栈中所有必要的finally块来清理其中启动的操作,展开调用堆栈。然后CLR才执行与抛出异常类型相匹配的catch块中的代码。未处理异常 登记AppDomain.CurrentDomain.UnhandledException事件可以处理当前应用程序域中的由托管代码抛出的未处理异常(不能处理非托管代码抛出的未处理异常)。该事件的委托原型为: public delegate void UnHandledExceptionEventHandler(o 阅读全文
posted @ 2011-03-30 13:48 辛勤的代码工 阅读(732) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(30):如何正确使用异常
摘要:类库开发人员使用异常的指导原则避免过多的finally块可以使用using语句来减少finally代码块。避免捕获所有异常如果我们设计的类型是一个类库的一部分,那么它绝对不应该捕获所有的异常(即捕获System.Exception),因为它不可能知道应用程序会如何处理这些异常。如果应用程序代码抛出了一个异常,应用程序的另一部分很可能期望能捕获该异常。这时我们应该让异常按照筛选器的筛选规则沿着调用堆栈向更高一层传递,直至找到能够处理它的应用程序代码。从异常中顺利的恢复我们捕获某个特定的异常时,应该完全理解导致抛出异常的情况,并清楚哪些异常类型继承自我们所捕获的异常。当异常无法修复时,回滚部分完成 阅读全文
posted @ 2011-03-30 11:30 辛勤的代码工 阅读(289) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(29):定义自己的异常类型与序列化类型
摘要:异常简介 C#只能抛出与CLS兼容的异常,即从System.Exception继承的异常类型。但CLR允许抛出任何类型的对象。C#为我们提供了一种特殊的catch块来捕获与CLS不兼容的异常: catch //这里没有指定异常筛选器{ //这里执行恢复代码 ....} 这样的catch块也可捕获任何与CLS兼容的异常。 finally块中的代码执行的是一些资源清理操作,这些清理操作通常是对应的try块中的行为所需要的。 异常是对程序接口隐含假设的一种违反。 在设计一个类型时,我们应该首先假设类型最常见的使用方式,然后设计其接口使之能够很好地处理这种情况。最后再考虑接口带来的隐含假设,并且当任何 阅读全文
posted @ 2011-03-30 10:50 辛勤的代码工 阅读(492) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(28):复制委托链上的委托对象、动态创建与调用委托
摘要:复制委托链上的委托对象 CLR默认的委托链调用处理在大多数情况下已经很好用了。但考虑一下以下的情况:希望获得委托链上每个回调方法的返回值?默认情况下我们只能获得最后一次调用的回调方法的返回值。被调用的委托中有一个抛出了异常。被调用的委托中有一个阻塞了很长时间。 由于委托链上的对象是按序调用的,所以如果有一个委托对象出了问题,将会阻止调用委托链上所有其他的委托对象。显然,这样的算法不够强健。 对于那些该算法不能满足的情况,MulticastDelegate类提供了一个实例方法GetInvocationList,我们可以使用它来显式调用委托链上的每一个委托对象。 该方法原型:public clas 阅读全文
posted @ 2011-03-29 22:49 辛勤的代码工 阅读(337) 评论(0) 推荐(0) 编辑
Microsoft.Net框架程序设计学习笔记(27):委托判等、委托链
摘要:委托判等 FCL中Delegate重写了Object的Equals虚方法,MulticastDelegate又重写了Delegate的Equals实现。MulticastDelegate重写的Equals方法在比较两个委托对象时会首先看它们的_target和_methodPtr字段是否都指向同样的对象和方法。如果这两个字段不匹配,那么返回false。如果这两个字段都匹配,那么再看两个委托对象是否为委托链表的头部(即_prec字段不为null)。如果两个委托对象的_prev字段指示的链表有相同的长度,且两个链表上对应委托对象的_target和_methodPtr字段也都互相匹配,那么Equals 阅读全文
posted @ 2011-03-29 22:09 辛勤的代码工 阅读(296) 评论(0) 推荐(0) 编辑

点击右上角即可分享
微信分享提示