Расширяемые объекты
Шаблон расширяемого объекта используется для расширения существующих классов среды выполнения при помощи новых функций или добавления нового состояния к объекту. Расширения, привязанные к одному из расширяемых объектов, позволяют использовать поведения на различных этапах обработки для получения доступа к общему состоянию и функциональности, привязанным к общему расширяемому объекту, к которому они могут получить доступ.
Шаблон T> IExtensibleObject<
Предусмотрено три интерфейса в шаблоне расширяемого объекта: 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();
}
}
}