可扩展对象
可扩展对象模式用于使用新功能扩展现有运行时类,或者向对象中添加新状态。 附加到可扩展对象之一的扩展名,在访问附加到公共可扩展对象的共享状态和功能过程的各个不同阶段启用行为,各可扩展对象可以访问该公共扩展对象。
IExtensibleObject<T> 模式
可扩展对象模式中有三个接口:IExtensibleObject<T>、IExtension<T> 和 IExtensionCollection<T>。
IExtensibleObject<T> 接口通过允许 IExtension<T> 对象自定义类型的功能的这些类型实现。
可扩展的对象允许动态聚合 IExtension<T> 对象。 以下接口确定 IExtension<T> 对象的特点:
public interface IExtension<T>
where T : IExtensibleObject<T>
{
void Attach(T owner);
void Detach(T owner);
}
类型限制保证仅为是 IExtensibleObject<T> 的类定义扩展名。 Attach 和 Detach 提供聚合或解聚的通知。
对于实现限制它们何时可能会添加到所有者中或从所有者中移除有效。 例如,可以完全禁止移除(这将禁止在所有者或扩展名处于某个特定状态时添加或移除扩展名)、禁止同时添加多个所有者,或者仅允许单个移除后进行单个添加。
IExtension<T> 不表示与其他标准托管接口进行的任何交互。 具体地说,所有者对象上的 IDisposable.Dispose 方法通常不与它的扩展名分离。
将扩展添加到集合时,将在扩展进入集合之前调用 Attach。 将扩展从集合中移除时,将在移除扩展后调用 Detach。 这意味着(假设进行了适当的同步),扩展只有在 Attach 和 Detach 之间时才能在集合中找到。
传递给 FindAll 或 Find 的对象不需要是 IExtension<T>(例如,可以传递任何对象),但返回的扩展名是 IExtension<T>。
如果集合中没有扩展是 IExtension<T>,则 Find 返回 null,且 FindAll 返回空集合。 如果多个扩展实现 IExtension<T>,则 Find 返回其中一个扩展。 从 FindAll 中返回的值是快照。
有两种主要方案。 第一个方案使用 Extensions 属性作为基于类型的字典插入对象状态,以使另一组件使用该类型进行查找。
第二个方案使用 Attach 和 Detach 属性使对象可以参与自定义行为,例如注册事件、监视状态转换等。
IExtensionCollection<T> 接口是允许按照其类型检索 IExtension<T> 的 IExtension<T> 对象集合。 IExtensionCollection<T>.Find 返回最近添加的对象,此对象是属于该类型的 IExtension<T>。
Windows Communication Foundation 中的可扩展对象
Windows Communication Foundation (WCF) 中有四个可扩展对象:
ServiceHostBase — 这是服务主机的基类。 此类的扩展名可用于扩展 ServiceHostBase 自身的行为,或者用于存储每个服务的状态。
InstanceContext — 此类将服务类型的实例与服务运行时相连。 它包含有关该实例的信息以及对 InstanceContext 的包含 ServiceHostBase 的引用。 此类的扩展名可用于扩展 InstanceContext 的行为,或者用于存储每个服务的状态。
OperationContext — 此类表示为每个操作收集的运行时的操作信息。 这包括的信息有:传入消息头、传入消息属性和传入安全标识,以及其他信息。 此类的扩展名可以扩展 OperationContext 的行为,也可以存储每个操作的状态。
IContextChannel — 此接口允检查 WCF 运行时生成的通道和代理的各个状态。 此类的扩展名可以扩展 IClientChannel 的行为,也可以使用它存储每个通道的状态。
下面的代码示例演示使用简单的扩展名来跟踪 InstanceContext 对象。
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Text;
namespace Microsoft.WCF.Documentation
{
public class MyInstanceContextInitializer : IInstanceContextInitializer
{
public void Initialize(InstanceContext instanceContext, Message message)
{
MyInstanceContextExtension extension = new MyInstanceContextExtension();
//Add your custom InstanceContext extension that will let you associate state with this instancecontext
instanceContext.Extensions.Add(extension);
}
}
//Create an Extension that will attach to each InstanceContext and let it retrieve the Id or whatever state you want to associate
public class MyInstanceContextExtension : IExtension<InstanceContext>
{
//Associate an Id with each Instance Created.
String instanceId;
public MyInstanceContextExtension()
{ this.instanceId = Guid.NewGuid().ToString(); }
public String InstanceId
{
get
{ return this.instanceId; }
}
public void Attach(InstanceContext owner)
{
Console.WriteLine("Attached to new InstanceContext.");
}
public void Detach(InstanceContext owner)
{
Console.WriteLine("Detached from InstanceContext.");
}
}
public class InstanceInitializerBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters)
{ }
//Apply the custom IInstanceContextProvider to the EndpointDispatcher.DispatchRuntime
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
MyInstanceContextInitializer extension = new MyInstanceContextInitializer();
endpointDispatcher.DispatchRuntime.InstanceContextInitializers.Add(extension);
}
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
{ }
public void Validate(ServiceEndpoint endpoint)
{ }
}
public class InstanceInitializerBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(InstanceInitializerBehavior); }
}
protected override object CreateBehavior()
{
return new InstanceInitializerBehavior();
}
}
}