以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 Dot NET,C#,ASP,VB 』  (http://bbs.xml.org.cn/list.asp?boardid=43)
----  包装很好,里面是什么? (转载)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=43&rootid=&id=11777)


--  作者:admin
--  发布时间:11/9/2004 2:25:00 AM

--  包装很好,里面是什么? (转载)


发信人: Jobs (温少), 信区: DotNET        
标  题: 包装很好,里面是什么? (转载)
发信站: BBS 水木清华站 (Wed May  2 00:49:49 2001)


包装很好,里面是什么?  
作者:Eric Gunnerson

原文URL:http://www.microsoft.com/china/msdn/voices/csharp02152001.asp

C# 中的类型
C# 和公共语言运行时 (CLR) 中有两种类型:引用类型(在 C# 中用类声明)和值
类型(在 C# 中用结构声明)。引用和值类型在几个重要方面有所不同。下表概括
了这些区别:

                引用(类)              值(结构)  

保留变量        引用                    实际值  
活动值          在堆中                  内联(在堆栈中或与对象内联)  
默认值          Null                    零  
= 表示          复制引用                复制值  

值类型“感觉上”象一个数据。它包括预定义数值类型以及用户定义的类型(如  
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。  


转向更简单的模型
在语言中同时使用引用和值两种类型是很重要的。值类型轻便高效,而引用类型适
用于面向对象的开发。但是,现在我们有两种类型,而我们需要的是更为简单的模
型,使用单一的、能够囊括所有可能值的类型。

这样一个通用基类能够:

调用任何值的虚函数。


写入能够存储任何值的集合类。


替代 OLE Automation Variant 类型。  
为实现这一目的,公共语言运行时采用一种方法让值类型在需要时转化为引用类型
,即通过称为包装的进程。被包装的类型是通用基类,可以被各种类型的对象引用




包装和解除包装

考虑下列代码:

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)需要检查多个位置。

// 方案 1
int total = 35;
DateTime date = DateTime.Now;
string s = String.Format("Your total was {0} on {1}", total, date);

// 方案 B
Hashtable t = new Hashtable();
t.Add(0, "zero");
t.Add(1, "one");

// 方案 c
DateTime d = DateTime.Now;
String s = d.ToString();

// 方案 IV
int[] a = new int[2];
a[0] = 33;
  

// 方案 101
ArrayList a = new ArrayList();
a.Add(33);

// 方案 vi
MyStruct s = new MyStruct(15);
IProcess ip = (IProcess) s;
ip.Process();

答案
请检查答案并记录分数。

方案 1
String.Format() 将字符串作为第一个参数,对象作为第二个和第三个参数。
int 和 DateTime 都是值类型,所以它们都将被包装以作为第二个和第三个参数。
String.Format() 使用这些参数,然后对每个参数调用 object.ToString() 将其
转换为字符串表示。如果您知道 int 将被包装,得一分;如果知道 DateTime 被
包装,得一分。

方案 B
Hashtable.Add() 有两个参数,一个是关键字,另一个是值。它们都是类型对象。
传递给关键字参数的值为整数,所以它必须被包装,才能作为对象传递。传递给值
参数的值为字符串(引用类型),所以字符串不需要包装。每一点判断正确各得一
分。

方案 c
这段代码很迷惑人。包装的目的之一是实现对值类型参数的虚函数调用。
ToString() 是对象的虚函数,所以,看起来在调用 ToString() 时,d 将被包装
。但是在转换对象时没有使用 d,所以不需要进行包装。编译器知道类型为  
DateTime 的变量只能为该类型(因为没有导出的值类型,所以该变量不能为导出
类型),所以它可以直接调用 DateTime.ToString(),并设置“这个”引用,使其
指向堆栈中的 d。如果回答正确,得一分。

方案 IV
CLR 中的数组直接保存它们的值。例如,一个有五个元素的 int 数组有足够的空
间保存 5 个 int,而不是 5 个对象。如果认为此代码与包装无关,得一分。

方案 101
ArrayList.Add() 将对象作为参数,所以整数 33 将被包装。如果回答正确,得一
分。

方案 vi
接口为引用类型,所以在将值类型强制转换到接口实现时,必须包装值类型。如果
了解这一点,得一分。

最后得分

将所有分数相加,并使用下表来检查对包装的了解程度:

        分数            说明  
        8               对包装很了解  
        6-7             了解,但有时明白,有时糊涂  
        3-5             尚可,请再接再厉  
        1-2             需要继续学习  
        0               尚未入门  



摘要
最后总结一下包装。包装使编写和使用具有通用对象参数的函数变得简单而直接。
和许多美好的事情一样,包装也有不好的一面。下个月,我们将讨论这些不好的方
面是什么,如何减少负面影响,以及对 C# 的进一步说明(这会让我们的 C# 生活
更加美好)。

C# Web 站点荟萃

http://www.csharphelp.com
http://dotnetwire.com

--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 210.39.3.110]
返回上一页
回到目录
回到页首
下一篇



W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
46.875ms