|
| |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
包装很好,里面是什么? 作者:Eric Gunnerson 上个月,我们花了一些时间来学习如何找到与 C# 有关的东西。我收到一些询问,问及有关 C# 或 .NET 的 Web 站点,所以我决定在专栏里增加一个 Web 站点荟萃节目。写信告诉我(ericgu@microsoft.com)您的站点,每个月我会随机选择五个站点,在专栏的最后列出它们的 URL。 开场白结束,言归正传。 C# 中的类型C# 和公共语言运行时 (CLR) 中有两种类型:引用类型(在 C# 中用类声明)和值类型(在 C# 中用结构声明)。引用和值类型在几个重要方面有所不同。下表概括了这些区别:
值类型“感觉上”象一个数据。它包括预定义数值类型以及用户定义的类型(如 Complex 数字、Point 或 Rectangle)。如上文所述,值类型的变量是实际的值,所以在您使用变量时,通常处理的是实际的值。 int i = 123;int j = i;i = 55; 在第二次指定变量后,两个独立的变量包含一样的值。修改 i 的值不会改变 j 的值。 引用类型用于所有不能用作值类型的对象。引用类型的变量指向堆中对象的实例。这意味着在将一个变量指定给另一个变量时,只是指定了引用,而不是值。 Employee e = new Employee("Fred");Employee f = e;f.Name = "Barney"; 在第二次指定变量后,e 和 f 指向同一对象。这意味着修改 f 的名称也将改变 e 的名称,因为它们引用同一实例。 这引发了一个相关话题。有些人可能一直希奇,为什么 System.String 类中的函数不修改字符串,而总是返回字符串的新副本。这是因为字符串的类型为引用类型。假如对字符串调用 s.Trim() 来修改内部字符串,您将碰到与 Employee 一样的问题(这对字符串异常糟糕)。 修改类值的成员称为“变更者”,而不具有任何变更者的类称为不可变类。不可变类的存在可以使类的行为类似于值类,但不能写入为值类。 假如您需要使用可变字符串类,请在 System.Text 中试用 StringBuilder。 转向更简朴的模型在语言中同时使用引用和值两种类型是很重要的。值类型轻巧高效,而引用类型适用于面向对象的开发。但是,现在我们有两种类型,而我们需要的是更为简朴的模型,使用单一的、能够囊括所有可能值的类型。 这样一个通用基类能够:
为实现这一目的,公共语言运行时采用一种方式让值类型在需要时转化为引用类型,即通过称为包装的进程。被包装的类型是通用基类,可以被各种类型的对象引用。 包装和解除包装考虑下列代码: int value = 123;object o = value; // 将 int 包装到对象中int value2 = (int) o; // 解除包装到 value2 当赋值给 o 时,作为赋值的一部分,C# 编译器将创建足够容纳堆中 int 的引用类型包装,将值复制到该包装,然后将包装标记为实际类型(此处为 System.Int32),以便运行时了解包装的类型。 要从包装中取值,必须使用强制类型装换来指定包装的类型(对象能够保留任何类型)。在执行过程中,运行时将检查对象变量引用的类型是否为强制类型转变中指定的类型。假如类型准确,值将从包装中复制回值类型变量。假如类型不准确,将导致非常。 请注重解除包装过程中不会进行其他转变;类型必须完全匹配。换句话说,假如我们编写代码: long value2 = (long) o; // 包装的值是 int 其中 o 为已包装的 int,则将导致非常。但是,我们可以这样编写: long value2 = (long)(int) o; 则转变将正常进行。 虽然这个示例演示了包装和解除包装,但可能会造成一些误解。编写代码进行包装的情况异常少见,一般是在将值类型的变量传递给类型对象参数时使用。 下面是一个小测验。希望大家专心做。 测验:您对包装了解多少?下面的代码段给出了不同方案。请阅读这些代码,判定哪一段代码涉及包装,而哪一段与包装无关。有些方案(如 B)需要检查多个位置。 // 方案 1int total = 35;DateTime date = DateTime.Now;string s = String.Format("Your total was {0} on {1}", total, date);// 方案 BHashtable t = new Hashtable();t.Add(0, "zero");t.Add(1, "one");// 方案 cDateTime d = DateTime.Now;String s = d.ToString();// 方案 IVint[] a = new int[2];a[0] = 33; // 方案 101ArrayList a = new ArrayList();a.Add(33);// 方案 viMyStruct s = new MyStruct(15);IProcess ip = (IProcess) s;ip.Process(); 答案请检查答案并记录分数。 方案 1String.Format() 将字符串作为第一个参数,对象作为第二个和第三个参数。int 和 DateTime 都是值类型,所以它们都将被包装以作为第二个和第三个参数。String.Format() 使用这些参数,然后对每个参数调用 object.ToString() 将其转变为字符串表示。假如您知道 int 将被包装,得一分;假如知道 DateTime 被包装,得一分。 方案 BHashtable.Add() 有两个参数,一个是要害字,另一个是值。它们都是类型对象。传递给要害字参数的值为整数,所以它必须被包装,才能作为对象传递。传递给值参数的值为字符串(引用类型),所以字符串不需要包装。每一点判定准确各得一分。 方案 c这段代码很疑惑人。包装的目的之一是实现对值类型参数的虚函数调用。ToString() 是对象的虚函数,所以,看起来在调用 ToString() 时,d 将被包装。但是在转变对象时没有使用 d,所以不需要进行包装。编译器知道类型为 DateTime 的变量只能为该类型(因为没有导出的值类型,所以该变量不能为导出类型),所以它可以直接调用 DateTime.ToString(),并设置“这个”引用,使其指向堆栈中的 d。假如回答准确,得一分。 方案 IVCLR 中的数组直接保存它们的值。例如,一个有五个元素的 int 数组有足够的空间保存 5 个 int,而不是 5 个对象。假如认为此代码与包装无关,得一分。 方案 101ArrayList.Add() 将对象作为参数,所以整数 33 将被包装。假如回答准确,得一分。 方案 vi接口为引用类型,所以在将值类型强制转变到接口实现时,必须包装值类型。假如了解这一点,得一分。 最后得分将所有分数相加,并使用下表来检查对包装的了解程度:
摘要最后总结一下包装。包装使编写和使用具有通用对象参数的函数变得简朴而直接。和许多美好的事情相同,包装也有不好的一面。下个月,我们将讨论这些不好的方面是什么,如何减少负面影响,以及对 C# 的进一步说明(这会让我们的 C# 生活更加美好)。 C# Web 站点荟萃下面的 Web 站点是我通过电子邮件获得的,不过我知道的仅此而已。假如那里的代码无法编译,计算机死机,或者碰到种种麻烦,请不要向我抱怨。 本月仅有两项:
返回类别: 教程 上一教程: .Net 下的Wondows窗体常用项目 下一教程: 使用 Visual Basic .NET 重载事件处理程序(zt) 您可以阅读与"包装很好,里面是什么(转自微软)"相关的教程: · asp+中的发送者是什么意思 · ADO+ 引导数据种类的演变(转自 ms 二) · 微软李开复:.NET实现后网络将不再是泡沫 · .NET里面的Interop太烂了 · Net:解读微软互联网新战略(上) |
| 快精灵印艺坊 版权所有 |
首页 |
||