本地的对象
所有的.NET对象默认都是本地的。这意味着一般的.NET对象是不能从创建它们的进程之外进行访问的。如果不在代码中采取额外的处理,是不可能把对象传递到其他进程或者其他电脑中的(一个叫做封送的过程),不管是以按值还是按引用的方式。
锚定的对象
在很多的技术中,包括COM,对象总是按引用来传递的。这意味着当你从一台电脑或进程向另外一个电脑或者进程“传递”一个对象的时候,该对象实际上仍然留在它原来的进程中,而且传递到那个进程或电脑的仅仅是得到了连接该对象的一个指针,或者叫引用。
其他的电脑可以通过这个引用来访问该对象。然而,因为该对象还在原来所在的电脑上,任何关于属性或者方法的调用都要在网络上传递,而且调用的结果也要通过网络返回。这种做法只有在对象的调用非常少的时候才有用;只调用一次是最理想的!MTS或者COM+对象的推荐设计方法提倡只用一个方法来做所有的事情就是因为这个原因,牺牲“良好”的面向对象设计来家少延时。
这种类型的对象固定在,或者是锚定在它最初被创建的电脑或者进程中。一个猫定的对象永远不会移动;它通过引用被外界访问。在.NET中,猫定的对象是通过继承MarshalByRefObjet来创建的。
{
}
在这之后,.NET框架会处理所有的底层细节。可以用远程调用来把这种类型的对象传递到另外一个进程或者电脑上,例如作为参数传递给一个方法,或者作为某个函数的的结果返回。
移动对象
通过远程调用、序列化和部署技术,.NET框架可以直接支持移动对象的概念。移动对象的概念依赖于对象可以被以按值的方法,在进程或者电脑之间传递的思想。这意味着对象从原来的进程或者电脑被物理的复制到其他进程或者电脑中。
以为那台被传递的电脑得到了一个该对象的拷贝,它可以在本地使用该对象。这意味着调用这样的对象的属性或者方法是非常高效的,没有额外的性能开销,唯一的开销就是第一次的时候通过网络把这个对象复制到本地。
注意:在网络上传递庞大的对象可能会造成性能上的问题。返回包含大量数据的DataSet会花很长的时间。这对象包含业务对象在内的移动对象也是如此。你在设计应用的时候要格外小心来避免提取非常大量的数据。
可以在进程或电脑之间移动的对象就是移动对象。移动对象的例子包括DataSet和业务对象。移动对象不固定在某个地方,而是可以移动到最需要他们的地方。要想在.NET中创建一个移动对象,在你的类定义中加入[Serializable]特性就可以了。你也可以实现ISerializable接口。
public class MyMobileClass
{
}
.NET框架同样会处理这部分的细节,使得这种对象可以被容易的作为参数传递给一个方法或者作为结果从函数返回。该对象会从原电脑被复制到调用端的电脑。
你一定要明白对象的代码并没有被自动的在网络上传递。在对象可以在电脑之间移动之前,双方的电脑必须安装包好该对象的.NET程序集。这样该对象的序列化数据才可以被.NET在网络上移动。安装所需的程序集这样的工作经常可以用ClickOnce或者其他的.NET部署技术来完成。
什么时候使用哪种机制
.NET框架对所有这三种机制都提供支持,可以供你选择来按照设计的需求创建自己的本地、锚定或者移动对象。
Windows Forms和Web Forms对象都是本地的-对于创建它们的进程以外的环境是不可访问的,这种情况下,我们不允许其他应用侵入你的程序和操纵你的UI对象。
锚定的对象非常重要,因为它们总是在某台特定的电脑上运行。如果你要编写一个访问数据库的对象,你会想让这个对象永远运行在某台拥有数据库访问权限的电脑上。因此,锚定的对象通常被用在应用服务器上。
另一方面,如果能根据需要从应用服务器移动到客户机或者Web服务器上,许多业务对象会变得更加有用。创建移动的业务对象,你就可以在电脑间传递聪明数据,从而在所有业务数据被传递的地方重用你的业务逻辑。
通常,锚定的对象和移动的对象会一起使用。用锚定对象来确保特定的方法是在这台服务器运行的。然后移动对象会被作为参数传递给这些方法,这会使得哪些移动对象从客户端移动到服务器。一些锚定的服务端方法会把移动对象作为结果返回,这时移动对象会从服务端移动会客户端。
按引用传递移动对象
这里有个术语很容易被人误解。模糊的把锚定的对象和“按引用传递”的概念联系在一起,把移动对象和“按值传递”联系在一起。从直觉来判断,这是对的。因为锚定的对象提供了一个引用,而移动对象则提供了那个实际的对象(和它的值)。
在分布式应用中,事情变得稍微复杂了些,但是原来的定义还是正确的:一个对象可以被按引用传递,来让所有的电脑都可以获得对服务器上同一个对象的引用。而且一个对象也可以按值传递,就是复制这个对象。但是如果你把一个标记了Serializable的对象故意按引用来传递,会发生什么呢?这个对象会被按值传递,但是.NET框架会试图让这个对象看起来好像是被按引用传递。
说得具体点, 就是这个对象按值被传递,通过网络复制了。区别在于这个对象在方法结束的时候会被返回给调用代码,而且对原对象的引用会被替换为对这个新返回的对象的引用。这么做,存在很大的危险。因为对该对象的其他引用仍然保持指向原来的对象,只有这一个特定的引用被更新。最后你可能会得到同一个对象的两个不同版本,一些引用指向旧的,一些指向这个新的。
注意:如果按引用传递了移动对象,在每次方法调用结束后一定要更新所有引用来确保使用该对象的最新版本。
你可以选择按值来传递移动对象,这样对象会被单向传递:从调用者到方法。或者你可以按引用传递移动对象,这样对象会被双向传递:从调用者到方法以及从方法返回调用者。如果你想得到任何方法对该对象的修改,就应该用“按引用传递”。如果你不关心或不想得到方法对该对象的修改,就应该用“按值传递”。
按引用传递移动对象有性能上的不足,它需要通过网络把对象传递回调用段电脑,所以要比按值传递要慢。