可延伸物件
可延伸物件模式是用於以新功能延伸現有的執行階段類別,或將新狀態新增至物件。 附加至其中一個可擴充物件的擴充功能會在處理程序中的各種不同階段啟用行為,以存取附加至它們可存取之一般可擴充物件的共用狀態與功能。
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> 不代表與其他標準 Managed 介面的任何互動。 特別是,擁有者物件上的 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 執行階段所建置的通道和 Proxy 檢查各個狀態。 這個類別的延伸可以延伸 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();
}
}
}