第3章 类型基础 (已看)
第4章 用类型编程 (已看)
第5章 实例 (已看)
第6章 方法 (已看)
第8章 域 (已看)
第1章 CLR是一个更好的COM
COM 回顾
公共语言运行库
编程模型的演进
我们走到哪儿了
第2章 组件
模块定义
CLR程序存在模块(module)中. 一个CLR模块是一个字节流, 通常作为一个文件存储在本地的文件系统中或者Web服务器上
CLR模块包含代码, 元数据和资源
- IMetaDataEmit 接口是低级的COM接口,可以用来由经典的C++编程生成模块元数据
- System.Reflection.Emit 命名空间是高级的类库,用来由任何CLR友好的语言编程生成元数据和CIL
- CodeDOM则工作在更高级的抽象层面上
程序集定义
程序集名字
公钥和程序集
CLR加载器
将名字解析成位置
我们走到哪儿了
第3章 类型基础
类型概述
类型是CLR程序的生成块(building block)
CLR类型(CLR type)是命名的可重用抽象体.CLR类型的描述存放在CLR模块的元数据中,该模块还包含使类型工作所需要的CIL或者本机代码.完全限定的CLR类型名包括三个部分: 程序集名字, 可选的命名空间前缀和类型名称
CTS有三种基本类型的成员: 字段,方法和嵌套类型. 其他类型成员(例如: 属性, 事件)是以附加元数据的形式出现的方法
默认情况下, 确切的内存布局是不透明的
类型和初始化
一个类型最多只有一个类型初始化器(.cctor),它没有参数和返回值,也不能被直接调用.它们是被CLR作为类型初始化的一部分自动调用的.
单个C#类型既可以有显式的类型初始化方法,又能有带初始化表达式的静态字段声明,这是合法的.当两者都存在时,作为结果的.cctor方法将以字段初始化开始(按照声明的顺序)
类型初始化器实际运行的时机,CLR将灵活处理.类型初始化器总是保证在首次访问类型的静态字段之前执行
当类型的实例每次被分配时,CLR将自动调用构造函数(constructor)(.ctor)
类型和接口
接口是整合到类型系统中的类型归类
从结构上来说,接口与其他类型的真正区别是,在类型的元数据上是否存在interface特性
类型和基类型
我们走到哪儿了
第4章 用类型编程
运行时的类型
CLR的每个对象都以一个固定大小的对象头开始,对象头不能通过程序直接访问, 但它确实存在
对象头有两个字段: 它的第一个字段是同步块(sync block)索引,你可以使用这个字段推迟该对象与附加资源的关联(例如, 锁, COM对象); 对象头的第二个字段是一个句柄(handle),它指向一个不透明的数据结构, 用于表示该对象的类型.
在CLR的当前实现中,对象引用总是指向对象头的类型句柄字段. 第一个用户自定义类型的字段总是sizeof(void*)字节, 不管对象引用指向哪里
给定类型的每个实例在对象头中都会有同样的类型句柄值. 类型句柄(type handle)简而言之是指向一个非透明的,无正式文档说明的数据结构的指针.这个数据结构包含了类型的完整描述,以及一个指向类型元数据的内存表示的指针.
CIL: isinst castclass
JIT编译器: JIT_IsInstance JIT_ChkCast
using System; public sealed class Util { public static void UseType() { // 获取类型对象 Type type = typeof(AcmeCorp.LOB.Customer); // 获取底层的类型句柄 RuntimeTypeHandle htype = type.TypeHandle; // 从该句柄还原类型对象 Type t2 = Type.GetTypeFromHandle(htype); // 现在, t2和type引用相同的System.Type对象 } }
using System; using System.Reflection; public sealed class Util { public static void UseType() { // 加载程序集 Assembly assm = Assembly.LoadFrom("C:\acme.dll"); // 获取类型对象 Type type = assm.GetType("AcmeCorp.LOB.Customer"); // 获取底层的类型句柄 RuntimeTypeHandle htype = type.TypeHandle; // 从该句柄还原类型对象 Type t2 = Type.GetTypeFromHandle(htype); // 现在, t2和type引用相同的System.Type对象 } }
using System; public sealed class Util { public static void DumpTypes(object o) { // 获取该对象的类型 Type type = o.GetType(); // 列出该类型直接的或者间接的基类型 for (Type c = type; c != null; c = c.BaseType) { Console.WriteLine(c.AssemblyQuaifiedName); } // 列出该类型显式的或者隐式的接口 Type[] itfs = type.GetInterfaces(); for (int i = 0; i < itfs.Length; i++) { Console.WriteLine(itfs[i].AssemblyQualifiedName); } } }
用元数据编程
using System; using System.Reflection; public sealed class Util { public static void DumpMembers(Type type) { // 获取类型的成员 MemberInfo[] members = type.GetMembers(); // 列出成员 for (int i = 0; i < members.Length; i++) { Console.WriteLine("{0} {1}", members[i].MemberType, members[i].Name); } } }
using System; using System.Reflection; public sealed class Util { public static void DumpMembers(Type type) { // 获取类型的成员 BindingFlags f = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Nonpublic | BindingFlags.FlattenHierarchy; MemberInfo[] members = type.GetMembers(f); // 列出成员 for(int i = 0; i < members.Length; i++) { Console.WriteLine("{0} {1} ", members[i].MemberType, members[i].Name); } } }
特殊的方法
元数据和可扩展性
[assembly: Red] [module: Green] [class: Blue] [Yellow] public sealed class Widget { [return: Cyan] [method: Magenta] [Black] public int Splat() { } }
自定义特性的存在与否不影响CLR对类型的处理.相反地,自定义特性处于一种休眠状态,等待程序使用反射和其他元数据接口去读取它们
namespace System.Reflection { // MemberInfo, ParameterInfo, Assembly和Module都支持该接口 public interface ICustomAttributeProvider { // 测试类型attType的特性存在与否 bool IsDefined(System.Type attType, bool inherited); // 返回与atttType兼容的所有特性 object[] GetCustomAttributes(System.Type attType, bool inherited); // 返回l类型无关的所有特性 object[] GetCustomAttributes(bool inherited); } }
using System; using System.Reflection; public sealed class Utils { static void DisplayMethodStatus(Type type) { foreach (MethodInfo m in type.GetMethods()) { Console.Write("{0} : ", m.Name); } // 检测DocumentedAttribute特性 if (m.IsDefined(typeof(DocumentedAttribute), true)) { Console.Write("Documented"); } else { Console.Write("Undocumented"); } // 检测TestedAttribute特性 if (m.IsDefined(typeof(TestedAttribute), true)) { Console.WriteLine(" - OK"); } else { Console.WriteLine(" - Broken"); } } }
using System; using System.Reflection; public sealed class Utils { static void DisplayMethodStatus2(Type type) { Type attType = typeof(DocumentedAttribute); foreach(MethodInfo m in type.GetMethods()) { Console.Write("{0} : ", m.Name); } // 检测DocumentedAttribute特性 if (!m.IsDefined(attType, true)) { Console.WriteLine("Undocumented"); continue; } object[] atts= m.GetCustomAttributes(attType, true); DocumentedAttribute att = (DocumentedAttribute)atts[0]; Console.WriteLine("{0} : {1} words [{2}]", att.Writer, att.WordCount, (attReviewed ?"ok": "hold" )); } }
我们走到哪儿了
第5章 实例
对象和值的比较
考虑到一致性,我们在这里将对象定义为: 被垃圾回收的(garage-collected, GC)对上的CLR类型的实例
值类型的实例不是对象, 因为它们既不以对象头开始,也不会在GC堆上分配明显的实体
定义新的值类型有两种方式, 一种是以System.ValueType为基类型的类型; 另一种是以System.Enum为基类型的类型
C#编译器不允许ValueType用作基类型
你不能给C#的struct指定显式的基类型, 即隐含的基类型总是 System.ValueType
变量,参数和字段
引用类型new->CIL newobj
值类型new->initobj
向方法传递参数是赋值的变体
按引用传递参数(在C#中用ref或out修饰符标识)
相等与同一
一般来说, 如果两个对象是相同类型的实例, 并且其中一个对象的各个字段匹配另一个对象的字段值, 那么这两个对象就是相等的(equivalent).
如果两个对象在内存中共享一个地址, 则它们便是同一的(identical)
GetHashCode 的默认实现并不保证唯一性或一致性,因此, 不能在进行散列时用作唯一对象标识符. 派生类必须用返回唯一散列代码的实现重写GetHashCode
克隆
MemberwiseClone 执行的是浅表副本(shallow copy), 这意味着它只是将原对象的每个字段的值拷贝到克隆体中. 如果字段是一个对象引用,那么, 拷贝的仅仅是这个引用, 而不是引用的对象
深层副本(deep copy)是指递归拷贝其字段所引用的所有对象
装箱
将值类型的实例"克隆"到堆上, 这个过程被称为装箱(boxing), 只要当一个值类型的实例被赋给一个对象引用变量, 参数或字段时,这个过程就会发生
using System; public interface IAdjustor { void Adjust(); } public struct Size: IAdjustor { public int height; public int width; public void Adjust() { height += 2; width += 3; } } public class App { static void Main() { Size s = new Size(); bool truth = s.height == 0 && s.width == 0; Console.WriteLine(truth); s.Adjust(); truth = s.height == 2 && s.width == 3; Console.WriteLine(truth); IAdjustor itf = s; // 装箱 itf.Adjust(); // 操作装箱的副本 truth = s.height == 2 && s.width == 3; Console.WriteLine(truth); s = (Size)itf; // 取消装箱 truth = s.height == 4 && s.width == 6; Console.WriteLine(truth); } }
数组
CLR支持两种复合类型: 一种是其成员可以通过局部的唯一名称访问; 另一种是其成员没有被命名,而是通过位置被访问.
数组是引用类型的实例, 这个引用类型是CLR基于数组的元素类型和数组的维数[也称为秩(rank)]合成的
对象生存期
终结
我们走到哪儿了
第6章 方法
方法和JIT编译
CLR只执行本机的机器码
将CIL转换到本机的机器码有两种解决的方法. 默认的场景是推迟转换, 直到该组件被加载到内存中时
方法调用和类型
接口,虚方法和抽象方法
显式方法调用
间接方法调用和委托
异步方法调用
方法终止
我们走到哪儿了
第7章 高级方法
动机
作为方法调用的消息
堆栈和消息转化
代理类型
消息过程(回顾)
对象和上下文
上下文和截获
我们走到哪儿了
第8章 域
执行范围和CLR
像进程一样, AppDomain是一个所有权(ownership)的单元 AppDomain的资源包括被加载的模块, 程序集和类型. 只要AppDomain被加载, 这些资源就一直在内存中. 卸载AppDomain是唯一卸载模块或者程序集的途径. 卸载AppDomain也是回收类型静态字段所占内存的唯一方式
CLR定义了一个类型System.Threading.Thread, 在AppDomain中表示为可调度的(schedulable)实体, System.Threading.Thread线程对象有时被引用为软线程(soft thread),原因是它的构造无法为底层操作系统所识别. 相比之下, OS线程被引用为硬线程(hard thread), 因为它们是由OS处理的
CLR维护硬线程的线程本地存储区(thread local storage TLS)中的一些信息. 特别是, 你会发现硬线程的TLS引用当前AppDomain和软线程对象
用AppDomain编程
using System.Security.Policy; namespace System { public sealed class AppDomain: MarshalByRefObject _AppDomain, System.Security.IEvidenceFactory { // 获得“当前"域 public static AppDomain CurrentDomain { get; }; // 获取/设置特定域的环境变量 public object GetData(string name); public void SetData(string name, object value); // 获取加载到域中的所有程序集 public Assembly] GetAssemblies() // 产生新的AppDomain public static AppDomain CreateDomain( string friendlyName, // 调试器的名字 Evidence secinfo, // 用于建立堆栈顶层的权限集 AppDomainSetup ldrinfo); // 包含AppDomain初始化信息的对象 // 卸载现存的AppDomain public static void Unload(AppDomain target); // 加载基于EXE的程序集和运行Main(同步) public int ExecuteAssembly(string assemblyFile, Evidence assemblySecurity, string[] argv); // 在目标AppDomain中执行方法 public void DoCallBack(CrossAppDomainDelegatecb); // 为了清晰明了, 其他成员省略 } }
ExecuteAssembly方法先将AppDomain转化为子域.如果指定的程序集调用AppDomain.CurrentDomain方法, 它将获取子AppDomain对象.如果指定的程序集使用与父程序相同的任何程序集,则子AppDomain将加载它自己独立的类型与模块拷贝,包括它自己的静态字段集合
using System;' public class MyApp { public static int Main(string[] argv) { // 创建域 AppDomain child = AppDomain.CreateDomain("childapp"); // 执行 yourapp.exe int r = child.ExecuteAssembly("yourapp.exe", null, argv); // 卸载域 AppDomain.Unload(child); // 返回结果 return r; } }
在AppDomain中还可以插入任意代码. AppDomain.DoCallBack方法允许你在一个类型上指定一个方法, 它将在外部域中执行. 这个指定方法必须是静态的,并且它的签名与CrossAppDomainDelegate签名匹配. 此外, 为了执行这段代码,将不得不加载外部AppDomain中的指定方法的类型,模块和程序集. 如果指定方法需要在AppDomain之间共享信息,那么,它可以在外部AppDomain上使用SetData和GetData方法
using System; using System.Diagnostics; using System.Reflection; public class MyApp { // 一个简单的例程,它将被加载的程序集的数目保存为一个AppDomain属性 public static void CallbackProc() { AppDomain current = AppDomain.CurrentDomain; Console.WriteLine(current.FriendlyName); current.SetData("XX_assmcount", current.GetAssemblies().Length); var assm = current.GetAssemblies(); foreach(var item in assm) { Console.WriteLine(item.FullName); } } // 这个例程开始工作 static int GetAssemblyCount(AppDomain target) { // 创建委托 CrossAppDomainDelegate cb = new CrossAppDomainDelegate(CallbackProc); // 插入并执行代码 target.DoCallBack(cb); // 提取这个属性 return (int)target.GetData("XX_assmcount"); } // 生成一个域并且插入代码 static void Main() { AppDomain child = AppDomain.CreateDomain("childapp", null, null); Console.WriteLine(GetAssemblyCount(child)); Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Length); var assm = AppDomain.CurrentDomain.GetAssemblies(); foreach (var item in assm) { Console.WriteLine(item.FullName); } AppDomain.Unload(child); } }
AppDomain事件
using System; class BadApp { // 这个方法是我们的处理程序 static void AppHurts(Object sender, UnhandledExceptionEventArgs args) { Exception offender = args.ExceptionObject as Exception; if (args.IsTerminating) { // CleanUpBeforeDying(); } } static void Main() { // 这将注册用于整个过程的处理程序 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(AppHurts); throw new Exception("Hello"); // int x = 3 / 0; // 导致异常 } }
AppDomain和程序集解析器
using System; public class Test1 { static void Main() { // 提取当前的域 AppDomain here = AppDomain.CurrentDomain; // 提取基目录路径的3种不同的方式 string dir1 = here.BaseDirectory; Console.WriteLine(dir1); string dir2 = here.SetupInformation.ApplicationBase; Console.WriteLine(dir2); string dir3 = (string)here.GetData("APPBASE"); Console.WriteLine(dir3); } }
AppDomain和代码管理
using System; public class MyApp { // 重写SingleDomain的默认方式 [LoaderOptimization(LoaderOptimization.MultiDomain)] public static void Main() { // 在这里生成域, 并开始工作 } }
AppDomain和对象(回顾)
你可能想将某个AppDomain的对象引用迁移到另一个域中 而这个对象引用又是AppDomain相关的 答案就是封送(marshaling)
CLR将所有对象,值和对象引用的作用域定为特定的AppDomain. 当需要将引用或者值传给另一个AppDomain时,首先必须封送它
System.Runtime.Remoting
System.Runtime.Remoting.RemotingServices.Marshal/Unmashal
using System; class App { static void Main() { // 创建域 AppDomain child = AppDomain.CreateDomain("c", null); // 在新的域中创建对象 Object proxy = child.CreateInstance("someassm", "Bob").Unwrap(); // 向下类型转换, 并且调用 Bob b = (Bob)proxy; b.f(); } }
using System; class App { static void Main() { // 创建两个域 AppDomain c1 = AppDomain.CreateDomain("c1", null); AppDomain c2 = AppDomain.CreateDomain("c2", null); // 在第一个域中创建对象 Object handle = c1.CreateInstance("someassm", "Bob"); // 在c2的属性中保存对象的句柄 c2.SetData("HeresYourHandle", handle); // 运行某个程序 c2.ExecuteAssembly("foo.exe", null, null); } }
我们走到哪儿了
第9章 安全性
组件和安全性
证据
策略
权限
实施
我们走到哪儿了
第10章 CLR外部环境
内存
基于CLR的程序按部就班地使用验证的指针. 这种指针被称为托管(managed)指针. C#和VB.NET编译器在方法参数声明为传引用时,就使用托管指针.不同于C风格指针,托管指针不支持算数运算. 托管指针是强类型的,其本身就是类型的实例. 例如,指向System.Int32的托管指针是 System.Int32&类型的实例.托管指针之所以称为"托管", 其最终原因是, 在堆压缩(heap compaction)过程中当被引用的对象被移动时, 垃圾回收器能够调整指针的值
CLR也支持第二种风格的指针, 即类似C风格的指针. 这种风格的指针被称为"非托管(unmanaged)"指针. 这里使用形容词"非托管", 是因为垃圾回收器在堆压缩时将忽略非托管指针. 同托管指针一样, 非托管指针也是某个类型的实例. 例如, 指向System.Int32非托管指针是System.Int32*类型的实例
为了编译使用非托管指针的C#程序,必须使用/unsafe或者/unsafe+命令行参数. 这个开关导致编译器发射请求SkipVerification权限的权限集. 这个开关也允许在程序的源代码中使用非托管指针
C#不鼓励使用非托管指针, 为此, 它要求非托管指针的使用只出现在一个被声明为unsafe的作用域(scope)内(例如, 方法作用域, 类型作用域)
执行模式
非托管模块
加载CLR
作为COM组件的CLR
我们走到哪儿了
词汇
.Net Framework: 用于编写基于CLR应用程序和XML Web Services的技术集
.Net Framework SDK: 可以免费下载的软件开发包, 用于编写和调试基于CLR的应用程序和XML Web Services
abnormal termination (异常终止): 由于没有处理抛出的异常, 方法只好仓促退出
abstract type (抽象类型): 只用作基类型的那些类型, 并且不能被用作实例化对象或值
AL.EXE: .Net Framework SDK中的程序集链接器
AppDomain: 在CLR中执行的基本作用域
aspect-oriented programming (AOP, 面向方面的编程): 这是一种编程技术. 它对于不同concern的代码进行分解, 经常基于out-of-band声明和代码注入等隐式地执行
assembly (程序集): 作为部署单位的一个或者多个模块的集合
assembly loader (程序集加载器): CLR中代码的核心部分, 它将程序集的模块映射到内存中
assembly reference (程序集引用): 外部程序集的引用, 它通常出现在程序集清单(manifest)中
assembly resolver (程序集解析器): CLR中代码的核心部分, 在调用程序集加载器加载程序集之前, 通过名字定位程序集
CASPOL.EXE: .Net Framework SDK的工具之一, 用于查看和控制安全策略.
CL.EXE: 随.Net Framework SDK一起发布的C++编译器
Common Intermediate Language (CIL, 公共中间语言): CLI使用的架构无关(architecture-neutral)的指令集
Common Language Infrastructure (CLI, 公共语言架构): 由ECMA批准的一组规范, 它描述了CLR的公开方面
Common Language Runtime (CLR, 公共语言运行库): Microsoft用于Windows(尤其是Windows.NET Server, Windows XP, Windows 2000, Windows NT4.0 SP6a或者之后的版本, Windows 98和Windows ME) 的CLI实现
Common Language Specification (CLS, 公共语言规范): CTS的子集, 所有与CLI兼容的编程语言都必须遵守它
Common type system (CTS, 通用类型系统): 语言无关的(language-neutral)类型系统, 用于CLI元数据和指令
Component Object Model (COM, 组件对象模型): 20世纪90年代兴起的组件技术, 用于将类型加到加载器和组件元数据中
Constructor (构造函数): 由CLR自动调用的方法, 用于初始化一个类型新的实例. 构造函数在结构上只是方法, 其方法名总是.ctor
Contract (约定): 描述组件之间交互关系的协议
CORDBG.EXE: 同.NET Framework一起发布的命令行式的调试器
CSC.EXE: 同.NET Framework一起发布的C#编译器
DBGCLR.EXE: 同.NET Framework一起发布的界面友好的调试器
delegate (委托): 委托是一个对象, 它的存在只是为了调用目标对象的特定方法
event (事件): 一组命名的方法集, 是注册事件处理程序的汇集点
event handler (事件处理程序): 与CLR事件一起注册的委托对象
evidance (证据): 有关程序集来源的证据, 这是由程序集加载器进行收集的, 并且对于给定代码段, 决定其安全策略
exception (异常): 在程序执行过程中, 用于标识异常状态的对象.
exception handler (异常处理程序): 用于处理由运行时隐式发出的或者throw语句显式发出的异常的代码
field (字段): 命名的, 类型化的存储单元, 它属于一个类型或模块
finalization (终止): 终止是通知对象其底层内存将要被回收的活动
FUSLOGVW.EXE: .NET Framework SDK的工具之一, 用于查看由程序集解析器编写的日志文件
GACUTIL.EXE: .NET Framework SDK的工具之一, 用于管理下载缓存和程序集缓存
garbage collection (垃圾回收): CLR对代码无所不知, 当它自动侦查到存在未使用的内存时, 就会进行资源的回收. 这种方式就是垃圾回收
Global Assembly Cache (GAC, 全局程序集缓存): 一个安全的,系统范围的代码缓存, 用于永久安装共享组件
hard thread (硬线程): 操作系统线程
IEEXEC.EXE: 通过IE启动基于CLR应用程序时所使用的宿主程序
ILASM.EXE: 同.NET Framework一起发布的CIL汇编器
ILDASM.EXE: .NET Framework SDK的工具之一, 用于显示模块与程序集的元数据与代码
Interface Definition Language (IDL, 接口定义语言): COM元数据的基于文本的格式
JSC.EXE: 同.NET Framework 一起发布的JavaScript编译器
loader (加载器): 用于定位和准备代码执行的代码部分
metadata (元数据): 在本书的上下文中, 元数据是描述组件的信息
method (方法): 命名的, 类型化的执行单元, 它属于一个类型或者模块
Microsoft Transaction Server (MTS, Microsoft事务服务器): COM的扩展,使用了类似AOP的技术, 提供了基于服务器端的服务
module (模块): 包含代码,资源和元数据的文件
NGEN.EXE: .NET Framework SDK的工具之一, 用于管理预编译的本机映像(native image)的缓存
normal termination (正常终止): 方法的正常执行, 当到最后一条语句时, 显式地或者隐式地返回
permission (权限): 执行受保护操作或者访问受保护资源的权力
Permission Set (权限集): 一个无序的权限集合
primitive type (基本数据类型): 也就是值类型. 它的值是原子的, 并且是CLR 所预先知道的12种内部类型之一(System.Boolean, System.Char, System.Double, System.Single, System.SByte, System.Int16, System.Int32, System.Int64, System.Byte和System.UInt16, System.UInt32和System.UInt64)
property (属性): 一组命名的方法集, 用于表示一个逻辑特性
public key (公钥): 一个大的,加密的唯一值, 用于标识一个用户或者组织,在CLR中主要用于识别程序集的开发者
public key token (公钥标记): 公钥的加密哈希(hash)值, 便于快速查询和比较公钥. 在CLR中主要用于降低完全限定的程序集引用的大小
reference type (引用类型): 对于其变量引用的是对象(潜在为null),而不是值, 这样的变量类型称为引用类型. 所有不直接或者间接派生于System.ValueType的类型都是引用类型
REGASM.EXE: .NET Framework SDK的工具之一, 用于将CLR程序集注册为COM组件
REGSVCS.EXE: .NET Framework SDK的工具之一, 用于通过COM+目录管理器注册CLR程序集
RESGEN.EXE: 同.NET Framework一起发布的资源编译器
sealed type (密封类型): 不能用作基类型的类型
security policy (安全策略): 基于证据, 将权限集授予代码的规则
shadow copying (影响拷贝): 程序集解析器的特征之一. 它加载的是程序集的拷贝, 这样就避免从底层文件中获取读锁
SN.EXE: .NET Framework SDK的工具之一, 用于管理公钥/私钥和程序集
SOAPSUDS.EXE: .NET Framework SDK的工具之一, 用于将Web服务的基于WSDL元数据转换为基于CLR的元数据. 参见WSDL.EXE
soft thread (软线程): System.Threading.Thread类型的CLR线程对象
strong name (强名称): 包含公钥(通常是指组件开发者的公钥)的程序集名称
termination handler (终止处理程序): 在离开受保护的指令范围之前,被保证运行的代码, 不管是否发生异常
thread local storage (TLS, 线程本地存储): 特定线程专用的数据
TLBEXP.EXE: .NET Framework SDK的工具之一, 用于将基于CLR的元数据转换为基于COM的元数据
TLBIMP.EXE: .NET Framework SDK的工具之一, 用于将基于COM的元数据转换为基于CLR的元数据
type (类型): 一个命名的抽象单元
type initializer (类型初始化器): 由CLR自动调用的方法, 用于初始化类型. 类型初始化器在结构上是方法, 其名字总是为.cctor
type library (TLB, 类型库): 基于COM元数据的二进制格式
uniform resource identifier (URI, 统一资源标识符): 能够唯一标识资源的基于文本的名字. URI既是统一资源定位符(URL), 也是统一资源名字(URN)
uniform resource locator (URL, 统一资源定位符): 包含定位提示的URI
uniform resource name (URN, 统一资源名字): 位置独立的URI
value type (值类型): 对于其变量是具体的实例, 而不是实例的引用, 这样的变量类型称为值类型. 所有的值类型都是直接或间接地由System.ValueType继承而来的
VBC.EXE: 同.NET Framework 一起发布的Visual Basic.NET编译器
version policy (版本策略): 确定组件间适用版本的规则集
Visual Studio.NET: Microsoft面向CLR的开发环境
WINCV.EXE: .NET Framework SDK的工具之一,用于浏览系统程序集的类型层次
WSDL.EXE: .NET Framework SDK的工具之一, 用于将基于CLR的元数据转换为Web服务的基于WSDL的元数据. 参见SOAPSUDS.EXE
XSD.EXE: .NET Framework SDK的工具之一, 用于实现基于XML模式的元数据与基于CLR的元数据之间的转换