| 

.NET C# Java Javascript Exception

0
Das Binden der Composable Parts wurde im 1. Teil ausführlich vorgestellt. Bei einer Anwendung kann es aber notwendig sein, solche Verbindungen gezielt wieder aufzulösen ohne gleich den ganzen Container zu löschen. Des weiteren werden Schnittstellen vorgestellt, die die Parts darüber informieren, ob deren Verbindung hergestellt, oder der Part komplett gelöscht wurde. Das Interface IPartImportsSatisfiedNotification Für [...]

Das Binden der Composable Parts wurde im 1. Teil ausführlich vorgestellt. Bei einer Anwendung kann es aber notwendig sein, solche Verbindungen gezielt wieder aufzulösen ohne gleich den ganzen Container zu löschen. Des weiteren werden Schnittstellen vorgestellt, die die Parts darüber informieren, ob deren Verbindung hergestellt, oder der Part komplett gelöscht wurde.


Das Interface IPartImportsSatisfiedNotification

Für die Parts kann es hilfreich sein zu erfahren, wann das Binden abgeschlossen ist. Hierzu wird die Schnittstelle IPartImportsSatisfiedNotification implementiert. Die Schnittstelle kann sowohl im Import, als auch im Export implementiert werden.

[Export(typeof(ICarContract))]
public class BMW : ICarContract, IPartImportsSatisfiedNotification
{
 // ...
 public void OnImportsSatisfied()
 {
 Console.WriteLine("BMW import is satisfied.");
 }
}
class Program : IPartImportsSatisfiedNotification
{
 [ImportMany(typeof(ICarContract))]
 private IEnumerable< Lazy< ICarContract > > CarParts { get; set; }

 static void Main(string[] args)
 {
 new Program().Run();
 }
 void Run()
 { 
 var catalog = new DirectoryCatalog(".");
 var container = new CompositionContainer(catalog);
 container.ComposeParts(this);
 foreach (Lazy< ICarContract > car in CarParts)
 Console.WriteLine(car.Value.StartEngine("Sebastian"));
 container.Dispose();
 }
 public void OnImportsSatisfied()
 {
 Console.WriteLine("CarHost imports are satisfied.");
 }
}

Beispiel 1 (Visual Studio 2010)

Bei der Ausführung des Programms wird nach container.ComposeParts() (Zeile 14) die Methode OnImportsSatisfied() aufgerufen. Wird zum ersten Mal auf ein Export zugegriffen, wird von diesem erst der Konstruktor, dann die Methode OnImportsSatisfied() und zum Schluss die Methode StartEngine() ausgeführt.

Die Reihenfolge der Methodenaufrufe ändert sich deutlich, wenn nicht mit der Klasse Lazy<T> gearbeitet wird. In diesem Fall wird nach der Methode container.ComposeParts() erst der Konstruktor und dann die Methode OnImportsSatisfied() von allen Exports ausgeführt. Erst zum Schluss wird OnImportsSatisfied() aufgerufen.

Die Verwendung von IDisposable

Wie in .NET üblich, sollten auch die Exports die Schnittstelle IDisposable implementieren. Da das Managed Extensibility Framework die Parts verwaltet, sollte auch nur der Container, der die Parts beinhaltet, Dispose() aufrufen. Wird vom Container Dispose() aufgerufen, so ruft er von allen Parts ebenfalls Dispose() auf. Deshalb ist es wichtig, die Methode Dispose() vom Container aufzurufen, wenn dieser nicht mehr benötigt wird.

Freigabe von Exports

Wurde die Erstellungsrichtinie (Creation Policy) auf NonShared gesetzt, so werden gleiche Exports mehrfach erstellt. Diese werden erst dann wieder freigegeben, wenn der gesamte Container mit der Methode Dispose() zerstört wird. Gerade bei lang lebigen Anwendungen kann dieses zu Problemen führen. Deshalb besitzt die Klasse CompositionContainer die Methoden ReleaseExports() und ReleaseExport(). ReleaseExports() zerstört alle Parts, während ReleaseExport() nur einzelne Parts freigibt. Bei der Freigabe wird von jedem Export Dispose() aufgerufen, wenn von diesem die Schnittstelle IDisposable implementiert wurde. Somit lassen sich gezielt Exports wieder aus dem Container entfernen, ohne den ganzen Container zerstören zu müssen. Die Methoden ReleaseExports() und ReleaseExport() können nur auf Exports angewendet werden, deren Erstellungsrichtlinie auf NonShared steht.

Bei dem folgenden Beispiel wurde in jedem Export die Schnittstelle IDisposable implementiert.

using System;
using System.ComponentModel.Composition;
using CarContract;
namespace CarBMW
{
 [Export(typeof(ICarContract))]
 public class BMW : ICarContract, IDisposable
 {
 private BMW()
 {
 Console.WriteLine("BMW constructor.");
 }
 public string StartEngine(string name)
 {
 return String.Format("{0} starts the BMW.", name);
 }
 public void Dispose()
 {
 Console.WriteLine("Disposing BMW.");
 }
 }
}

Der Host bindet zuerst alle Exports auf den Import. Nach dem Aufruf der Methode StartEngine() werden alle Exports durch die Methode ReleaseExports() wieder freigegeben. Nach erneutem Binden der Exports auf den Import werden dieses Mal die Exports einzeln entfernt. Zum Schluss wird durch die Methode Dispose() der Container zerstört.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using CarContract;
namespace CarHost
{
 class Program
 {
 [ImportMany(typeof(ICarContract), RequiredCreationPolicy = CreationPolicy.NonShared)]
 private IEnumerable< Lazy< ICarContract > > CarParts { get; set; }

 static void Main(string[] args)
 {
 new Program().Run();
 }
 void Run()
 { 
 var catalog = new DirectoryCatalog(".");
 var container = new CompositionContainer(catalog);

 container.ComposeParts(this);
 foreach (Lazy< ICarContract > car in CarParts)
 Console.WriteLine(car.Value.StartEngine("Sebastian"));

 Console.WriteLine("");
 Console.WriteLine("ReleaseExports.");
 container.ReleaseExports< ICarContract >(CarParts);
 Console.WriteLine("");

 container.ComposeParts(this);
 foreach (Lazy< ICarContract > car in CarParts)
 Console.WriteLine(car.Value.StartEngine("Sebastian"));

 Console.WriteLine("");
 Console.WriteLine("ReleaseExports.");
 foreach (Lazy< ICarContract > car in CarParts)
 container.ReleaseExport< ICarContract >(car);

 Console.WriteLine("");
 Console.WriteLine("Dispose Container.");
 container.Dispose();
 }
 }
}

Die Ausgabe des Programms sieht dementsprechend wie folgt aus:

CommandWindowSample02

Beispiel 2 (Visual Studio 2010)

Ausblick

Im 4. Teil geht es um Vererbung bei den Composable Parts. Wie verhält sich MEF, wenn Klassen das Attribut Import oder Export enthalten und diese Klassen innerhalb einer Vererbungshierarchie enthalten sind.


mef managed-extensibility-framework composable-parts lifecycle ipartimportssatisfiednotification releaseexport
Weitere News:
Schreibe einen Kommentar:
Themen:
releaseexport ipartimportssatisfiednotification lifecycle composable-parts managed-extensibility-framework mef
Entweder einloggen... ...oder ohne Wartezeit registrieren
Benutzername
Passwort
Passwort wiederholen
E-Mail