Obiekty rozszerzalne

Rozszerzalny wzorzec obiektu służy do rozszerzania istniejących klas środowiska uruchomieniowego o nowe funkcje lub dodawania nowego stanu do obiektu. Rozszerzenia, dołączone do jednego z rozszerzalnych obiektów, umożliwiają zachowanie na bardzo różnych etapach przetwarzania w celu uzyskania dostępu do stanu udostępnionego i funkcji dołączonych do wspólnego rozszerzalnego obiektu, do którego mogą uzyskiwać dostęp.

Wzorzec IExtensibleObject<T>

Istnieją trzy interfejsy w rozszerzalnym wzorcu obiektu: IExtensibleObject<T>, IExtension<T>i IExtensionCollection<T>.

Interfejs IExtensibleObject<T> jest implementowany przez typy, które umożliwiają IExtension<T> obiektom dostosowywanie ich funkcjonalności.

Rozszerzalne obiekty umożliwiają dynamiczną IExtension<T> agregację obiektów. IExtension<T> obiekty charakteryzują się następującym interfejsem:

public interface IExtension<T>
where T : IExtensibleObject<T>
{
    void Attach(T owner);
    void Detach(T owner);
}

Ograniczenie typu gwarantuje, że rozszerzenia można zdefiniować tylko dla klas, które są IExtensibleObject<T>. Attach i Detach podaj powiadomienie o agregacji lub dezagregacji.

Implementacje są prawidłowe, aby ograniczyć ich możliwość dodania i usunięcia z właściciela. Na przykład można całkowicie uniemożliwić usunięcie, nie zezwalając na dodawanie lub usuwanie rozszerzeń, gdy właściciel lub rozszerzenie znajdują się w określonym stanie, nie zezwalaj na dodawanie do wielu właścicieli jednocześnie lub zezwalaj tylko na pojedyncze dodanie, po którym następuje pojedyncze usunięcie.

IExtension<T> nie oznacza żadnych interakcji z innymi standardowymi interfejsami zarządzanymi. W szczególności IDisposable.Dispose metoda obiektu właściciela zwykle nie odłącza swoich rozszerzeń.

Po dodaniu rozszerzenia do kolekcji Attach jest wywoływane przed przejściem do kolekcji. Gdy rozszerzenie zostanie usunięte z kolekcji, Detach jest wywoływane po jego usunięciu. Oznacza to ,że (przy założeniu odpowiedniej synchronizacji) rozszerzenie może liczyć tylko na to, że znajduje się w kolekcji, gdy znajduje się między Attach i Detach.

Obiekt przekazany lub FindAllFind nie musi być IExtension<T> (na przykład można przekazać dowolny obiekt), ale zwrócone rozszerzenie jest IExtension<T>.

Jeśli w kolekcji nie ma IExtension<T>rozszerzenia , Find zwraca wartość null i FindAll zwraca pustą kolekcję. Jeśli implementuje IExtension<T>się wiele rozszerzeń, Find zwraca jeden z nich. Wartość zwrócona z FindAll elementu to migawka.

Istnieją dwa główne scenariusze. Pierwszy scenariusz używa Extensions właściwości jako słownika opartego na typie, aby wstawić stan na obiekcie, aby umożliwić innemu składnikowi wyszukiwanie go przy użyciu typu.

W drugim scenariuszu użyto Attach właściwości i Detach , aby umożliwić obiektowi uczestnictwo w niestandardowym zachowaniu, takim jak rejestrowanie w przypadku zdarzeń, obserwowanie przejść stanu itd.

Interfejs IExtensionCollection<T> jest kolekcją IExtension<T> obiektów, które umożliwiają pobieranie elementu IExtension<T> według jego typu. IExtensionCollection<T>.Find Zwraca ostatnio dodany obiekt, który jest IExtension<T> tego typu.

Rozszerzalne obiekty w programie Windows Communication Foundation

W programie Windows Communication Foundation (WCF) istnieją cztery rozszerzalne obiekty:

  • ServiceHostBase — jest to klasa bazowa hosta usługi. Rozszerzenia tej klasy mogą służyć do rozszerzania zachowania ServiceHostBase samego siebie lub przechowywania stanu dla każdej usługi.

  • InstanceContext — Ta klasa łączy wystąpienie typu usługi ze środowiskiem uruchomieniowym usługi. Zawiera on informacje o wystąpieniu, a także odwołanie do elementu zawierającego InstanceContextServiceHostBaseelement . Rozszerzenia tej klasy mogą służyć do rozszerzania zachowania InstanceContext klasy lub do przechowywania stanu dla każdej usługi.

  • OperationContext — Ta klasa reprezentuje informacje o operacji zbierane przez środowisko uruchomieniowe dla każdej operacji. Obejmuje to informacje, takie jak nagłówki komunikatów przychodzących, właściwości komunikatów przychodzących, tożsamość zabezpieczeń przychodzących i inne informacje. Rozszerzenia tej klasy mogą rozszerzać zachowanie OperationContext lub przechowywać stan dla każdej operacji.

  • IContextChannel — Ten interfejs umożliwia inspekcję każdego stanu kanałów i serwerów proxy utworzonych przez środowisko uruchomieniowe programu WCF. Rozszerzenia tej klasy mogą rozszerzyć zachowanie IClientChannel lub użyć ich do przechowywania stanu dla każdego kanału.

Poniższy przykład kodu przedstawia użycie prostego rozszerzenia do śledzenia InstanceContext obiektów.

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();
    }
  }
}

Zobacz też