.NET 上下文(Context)
.NET上下文的概念
应用程序域是进程中承载程序集的逻辑分区,在应用程序域当中,存在更细粒度的用于承载.NET对象的实体,那就.NET上下文Context。
所有的.NET对象都存在于上下文当中,每个AppDomain当中至少在于一个默认上下文(context 0)。
一般不需要指定特定上下文的对象被称为上下文灵活对象(context-agile),建立此对象不需要特定的操作,只需要由CLR自行管理,一般这些对象都会被建立在默认上下文当中。
透明代理
在上下文的接口当中存在着一个消息接收器负责检测拦截和处理信息,当对象是MarshalByRefObject的子类的时候,CLR将会建立透明代理,实现对象与消息之间的转换。 这里要特别说明一下,派生自MarshalByRefObjects 的类被绑定在应用程序域中。在应用程序域外,访问对象时需要代理。派生自ContextBoundObject(它又派生自MarshalByRefObjects)的类被限制在上下文中。在上下文之外,访问对象时需要代理。
应用程序域是CLR中资源的边界,一般情况下,应用程序域中的对象不能被外界的对象所访问。而MarshalByRefObject 的功能就是允许在支持远程处理的应用程序中跨应用程序域边界访问对象,在使用.NET Remoting远程对象开发时经常使用到的一个父类。
上下文绑定
当系统需要对象都使用消息接收器机制的时候,即可使用ContextBoundObject类。ContextBoundObject继承了MarshalByRefObject类,保证了它的子类都会通过透明代理被访问。
一般类所建立的对象为上下文灵活对象(context-agile),
它们都由CLR自动管理,可存在于任意的上下文当中。而 ContextBoundObject 的子类所建立的对象只能在建立它的对应上下文中正常运行,此状态被称为上下文绑定。
其他对象想要访问ContextBoundObject 的子类对象时,都只能通过代透明理来操作。
下面写个小例子来对比上下文绑定对象与上下文灵活对象
1 public class Example 2 { 3 public void Test() 4 { 5 ContextMessage("Example Test\n"); 6 } 7 //访问上下文绑定对象测试 8 public void Sync(ContextBound contextBound) 9 { 10 contextBound.Test("Example call on contextBound\n"); 11 } 12 }
首先创建了一个普通类Example,它的对象会运行在默认上下文当中。
1 [Synchronization] 2 public class ContextBound : ContextBoundObject 3 { 4 public void Test(string message) 5 { 6 ContextMessage(message); 7 } 8 }
ContextBound类继承了ContextBoundObject,它的对象是一个上下文绑定对象。
ContextBound还有一个Synchronization特性,此特性会保证ContextBound对象被加载到一个线程安全的上下文当中运行。
另外,Context类存在ContextProperties属性,通过此属性可以获取该上下文的已有信息。
1 //显示上下文信息 2 public static void ContextMessage(string data) 3 { 4 Context context = Thread.CurrentContext; 5 Console.WriteLine(string.Format("{0}ContextId is {1}", data, context.ContextID)); 6 foreach (var prop in context.ContextProperties) 7 { 8 Console.WriteLine(prop.Name); Console.WriteLine(); 9 } 10 } 11 12 static void Main(string[] args) 13 { 14 Example example = new Example(); 15 example.Test(); 16 ContextBound contextBound = new ContextBound(); 17 contextBound.Test("ContentBound Test\n"); 18 example.Sync(contextBound); 19 Console.ReadKey(); 20 }
运行结果:
由运行结果可以发现,example对象一般只会工作于默认上下文context 0 当中,而contextBound则会工作于线程安全的上下文 context 1当中。当example需要调用contextBound对象时,就会通过透明代理把消息直接传递到context 1中。