可扩展对象模式用于扩展具有新功能的现有运行时类或向对象添加新状态。 附加到可扩展对象之一的扩展名,在访问附加到公共可扩展对象的共享状态和功能过程的各个不同阶段启用行为,各可扩展对象可以访问该公共扩展对象。
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.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
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()
{ _instanceId = Guid.NewGuid().ToString(); }
public string InstanceId => _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();
}
}
}