Freigeben über


Verwaltetes Erweiterbarkeits-Framework (MEF)

Dieser Artikel enthält eine Übersicht über das managed Extensibility Framework, das in .NET Framework 4 eingeführt wurde.

Was ist MEF?

Das Managed Extensibility Framework (MEF) ist eine Bibliothek zum Erstellen einfacher und erweiterbarer Anwendungen. Es ermöglicht Anwendungsentwicklern, Erweiterungen ohne erforderliche Konfiguration zu ermitteln und zu verwenden. Außerdem können Erweiterungsentwickler Code einfach kapseln und fragile harte Abhängigkeiten vermeiden. MEF ermöglicht nicht nur die Wiederverwendung von Erweiterungen innerhalb von Anwendungen, sondern auch für alle Anwendungen.

Das Problem der Erweiterbarkeit

Stellen Sie sich vor, Sie sind der Architekt einer großen Anwendung, die Unterstützung für die Erweiterbarkeit bereitstellen muss. Ihre Anwendung muss eine potenziell große Anzahl kleinerer Komponenten enthalten und ist für die Erstellung und Ausführung verantwortlich.

Der einfachste Ansatz für das Problem besteht darin, die Komponenten als Quellcode in Ihre Anwendung einzuschließen und sie direkt aus Ihrem Code aufzurufen. Dies hat eine Reihe offensichtlicher Nachteile. Am wichtigsten ist, dass Sie keine neuen Komponenten hinzufügen können, ohne den Quellcode zu ändern, eine Einschränkung, die beispielsweise in einer Webanwendung akzeptabel sein kann, aber in einer Clientanwendung nicht funktioniert. Ebenso problematisch ist es, dass Sie keinen Zugriff auf den Quellcode für die Komponenten haben, da sie möglicherweise von Dritten entwickelt werden, und aus demselben Grund können Sie nicht zulassen, dass sie auf Ihre Komponenten zugreifen können.

Ein etwas komplexerer Ansatz wäre die Bereitstellung eines Erweiterungspunkts oder einer Schnittstelle, um die Entkopplung zwischen der Anwendung und den zugehörigen Komponenten zu ermöglichen. Unter diesem Modell können Sie eine Schnittstelle bereitstellen, die eine Komponente implementieren kann, und eine API, mit der sie mit Ihrer Anwendung interagieren kann. Dies löst das Problem der Anforderung des Quellcodezugriffs, hat aber immer noch eigene Schwierigkeiten.

Da die Anwendung keine Kapazität für die eigene Erkennung von Komponenten aufweist, muss sie dennoch explizit angewiesen werden, welche Komponenten verfügbar sind und geladen werden sollten. Dies erfolgt in der Regel durch die explizite Registrierung der verfügbaren Komponenten in einer Konfigurationsdatei. Dies bedeutet, dass die Sicherheit, dass die Komponenten korrekt sind, zu einem Wartungsproblem wird, insbesondere, wenn es sich um den Endbenutzer und nicht um den Entwickler handelt, der die Aktualisierung durchführen soll.

Darüber hinaus sind Komponenten nicht in der Lage, miteinander zu kommunizieren, außer durch die starr definierten Kanäle der Anwendung selbst. Wenn der Anwendungsarchitekt die Notwendigkeit einer bestimmten Kommunikation nicht erwartet hat, ist es in der Regel unmöglich.

Schließlich müssen die Komponentenentwickler eine harte Abhängigkeit davon akzeptieren, welche Assembly die von ihnen implementierte Schnittstelle enthält. Dies erschwert die Verwendung einer Komponente in mehr als einer Anwendung und kann auch Probleme verursachen, wenn Sie ein Testframework für Komponenten erstellen.

Was MEF bietet

Statt dieser expliziten Registrierung verfügbarer Komponenten bietet MEF eine Möglichkeit, sie implizit über die Zusammensetzung zu ermitteln. Eine MEF-Komponente, die als Teil bezeichnet wird, gibt deklarativ sowohl ihre Abhängigkeiten (als Importe bezeichnet) als auch welche Funktionen (als Exporte bezeichnet) zur Verfügung gestellt werden. Wenn ein Teil erstellt wird, erfüllt das MEF-Kompositionsmodul seine Importe mit dem, was aus anderen Teilen verfügbar ist.

Dieser Ansatz löst die im vorherigen Abschnitt erörterten Probleme. Da MEF-Teile ihre Funktionen deklarativ angeben, sind sie zur Laufzeit auffindbar, was bedeutet, dass eine Anwendung Teile ohne hartcodierte Verweise oder fragile Konfigurationsdateien verwenden kann. MIT MEF können Anwendungen Teile anhand ihrer Metadaten ermitteln und untersuchen, ohne sie zu instanziieren oder sogar ihre Assemblys zu laden. Daher muss nicht sorgfältig angegeben werden, wann und wie Erweiterungen geladen werden sollen.

Zusätzlich zu den bereitgestellten Exporten können von einem Teil seine Importe angegeben werden, die von anderen Teilen ausgefüllt werden. Dies macht die Kommunikation zwischen Teilen nicht nur möglich, sondern einfach und ermöglicht eine gute Faktorierung von Code. Dienste, die vielen Komponenten gemeinsam sind, können z. B. in einen separaten Teil integriert und einfach geändert oder ersetzt werden.

Da das MEF-Modell keine feste Abhängigkeit von einer bestimmten Anwendungsassembly erfordert, können Erweiterungen von Anwendung zu Anwendung wiederverwendet werden. Dies erleichtert auch die Entwicklung eines Testgerüsts, unabhängig von der Anwendung, zum Testen von Erweiterungskomponenten.

Eine erweiterbare Anwendung, die mit MEF geschrieben wird, deklariert einen Import, der von Erweiterungskomponenten gefüllt werden kann, und kann auch Exporte deklarieren, um Anwendungsdienste für Erweiterungen verfügbar zu machen. Jede Erweiterungskomponente deklariert einen Export und kann auch Importe deklarieren. Auf diese Weise sind Erweiterungskomponenten selbst automatisch erweiterbar.

Wo MEF verfügbar ist

MEF ist ein integraler Bestandteil von .NET Framework 4 und ist überall verfügbar, wo .NET Framework verwendet wird. Sie können MEF in Ihren Clientanwendungen verwenden, unabhängig davon, ob sie Windows Forms, WPF oder eine andere Technologie verwenden, oder in Serveranwendungen, die ASP.NET verwenden.

MEF und MAF

In früheren Versionen von .NET Framework wurde das verwaltete Add-In Framework (MAF) eingeführt, das es Anwendungen ermöglicht, Erweiterungen zu isolieren und zu verwalten. Der Fokus von MAF liegt auf einer etwas höheren Ebene als MEF und konzentriert sich auf die Isolierung von Erweiterungen sowie das Laden und Entladen von Assemblies, während MEF seinen Schwerpunkt auf Auffindbarkeit, Erweiterbarkeit und Portabilität legt. Die beiden Frameworks funktionieren reibungslos, und eine einzelne Anwendung kann beides nutzen.

SimpleCalculator: Beispielanwendung

Die einfachste Möglichkeit, zu sehen, was MEF tun kann, besteht darin, eine einfache MEF-Anwendung zu erstellen. In diesem Beispiel erstellen Sie einen sehr einfachen Rechner namens SimpleCalculator. Das Ziel von SimpleCalculator besteht darin, eine Konsolenanwendung zu erstellen, die grundlegende arithmetische Befehle in Form "5+3" oder "6-2" akzeptiert und die richtigen Antworten zurückgibt. Mit MEF können Sie neue Operatoren hinzufügen, ohne den Anwendungscode zu ändern.

Informationen zum Herunterladen des vollständigen Codes für dieses Beispiel finden Sie im SimpleCalculator-Beispiel (Visual Basic).

Hinweis

Der Zweck von SimpleCalculator besteht darin, die Konzepte und Syntax von MEF zu veranschaulichen, anstatt notwendigerweise ein realistisches Szenario für die Verwendung bereitzustellen. Viele der Anwendungen, die am meisten von der Leistungsfähigkeit von MEF profitieren würden, sind komplexer als SimpleCalculator. Ausführlichere Beispiele finden Sie im Managed Extensibility Framework auf GitHub.

  • Erstellen Sie zunächst in Visual Studio ein neues Konsolenanwendungsprojekt, und nennen Sie es SimpleCalculator.

  • Fügen Sie einen Verweis auf die System.ComponentModel.Composition-Assembly hinzu, in der sich MEF befindet.

  • Öffnen Sie Module1.vb oder Program.cs, und fügen Sie Imports oder using Richtlinien für System.ComponentModel.Composition und System.ComponentModel.Composition.Hosting hinzu. Diese beiden Namespaces enthalten MEF-Typen, die Sie zum Entwickeln einer erweiterbaren Anwendung benötigen.

  • Wenn Sie Visual Basic verwenden, fügen Sie das Public Schlüsselwort der Zeile hinzu, die das Module1 Modul deklariert.

Kompositionscontainer und Kataloge

Der Kern des MEF-Kompositionsmodells ist der Kompositionscontainer, der alle verfügbaren Teile enthält und die Komposition durchführt. Die Zusammensetzung ist das Abstimmen der Importe auf die Exporte. Der gängigste Typ des Kompositionscontainers ist CompositionContainer, und Sie verwenden diese für SimpleCalculator.

Wenn Sie Visual Basic verwenden, fügen Sie in Program eine öffentliche Klasse hinzu.

Fügen Sie der Klasse in Program oder Program.cs die folgende Zeile hinzu:

Dim _container As CompositionContainer
private CompositionContainer _container;

Um die verfügbaren Teile zu ermitteln, nutzt die Kompositionscontainer einen Katalog. Ein Katalog ist ein Objekt, das aus einer Quelle ermittelte Teile zur Verfügung stellt. MEF stellt Kataloge bereit, um Teile eines bereitgestellten Typs, einer Assembly oder eines Verzeichnisses zu ermitteln. Anwendungsentwickler können ganz einfach neue Kataloge erstellen, um Teile aus anderen Quellen zu ermitteln, z. B. einen Webdienst.

Fügen Sie der Program Klasse den folgenden Konstruktor hinzu:

Public Sub New()
    ' An aggregate catalog that combines multiple catalogs.
     Dim catalog = New AggregateCatalog()

    ' Adds all the parts found in the same assembly as the Program class.
    catalog.Catalogs.Add(New AssemblyCatalog(GetType(Program).Assembly))

    ' Create the CompositionContainer with the parts in the catalog.
    _container = New CompositionContainer(catalog)

    ' Fill the imports of this object.
    Try
        _container.ComposeParts(Me)
    Catch ex As CompositionException
        Console.WriteLine(ex.ToString)
    End Try
End Sub
private Program()
{
    try
    {
        // An aggregate catalog that combines multiple catalogs.
        var catalog = new AggregateCatalog();
        // Adds all the parts found in the same assembly as the Program class.
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

        // Create the CompositionContainer with the parts in the catalog.
        _container = new CompositionContainer(catalog);
        _container.ComposeParts(this);
    }
    catch (CompositionException compositionException)
    {
        Console.WriteLine(compositionException.ToString());
    }
}

Der Aufruf an ComposeParts sorgt dafür, dass der Kompositionscontainer einen bestimmten Satz von Teilen zusammensetzt, in diesem Fall die aktuelle Instanz von Program. Zu diesem Zeitpunkt geschieht jedoch nichts, da Program keine Importe zu füllen hat.

Importe und Exporte mit Attributen

Importieren Sie zunächst mithilfe von Program einen Rechner. Dies ermöglicht die Trennung von Benutzeroberflächenkomponenten, z. B. der Konsolenein- und -ausgabe, die an Program geleitet werden, von der Logik des Rechners.

Fügen Sie der Program-Klasse folgenden Code hinzu:

<Import(GetType(ICalculator))>
Public Property calculator As ICalculator
[Import(typeof(ICalculator))]
public ICalculator calculator;

Beachten Sie, dass die Deklaration des calculator Objekts nicht ungewöhnlich ist, sondern dass sie mit dem ImportAttribute Attribut versehen ist. Dieses Attribut deklariert etwas als Import; d. h., es wird vom Kompositionsmodul gefüllt, wenn das Objekt zusammengesetzt wird.

Jeder Import verfügt über einen Vertrag, der bestimmt, mit welchen Exporten es abgeglichen wird. Der Vertrag kann eine explizit angegebene Zeichenfolge sein, oder er kann automatisch von MEF aus einem bestimmten Typ generiert werden, in diesem Fall die Schnittstelle ICalculator. Jeder Export, der mit einem übereinstimmenden Vertrag deklariert wurde, erfüllt diesen Import. Beachten Sie, dass dies nicht erforderlich ist, während der Typ des calculator Objekts tatsächlich ICalculatorist. Der Vertrag ist unabhängig vom Typ des importobjekts. (In diesem Fall könnten Sie typeof(ICalculator) weglassen. MEF wird automatisch annehmen, dass der Vertrag auf dem Typ des Imports basiert, es sei denn, Sie geben ihn explizit an.)

Fügen Sie dem Modul oder dem SimpleCalculator-Namespace diese sehr einfache Schnittstelle hinzu:

Public Interface ICalculator
    Function Calculate(input As String) As String
End Interface
public interface ICalculator
{
    string Calculate(string input);
}

Nachdem Sie nun definiert ICalculatorhaben, benötigen Sie eine Klasse, die sie implementiert. Fügen Sie dem Modul oder SimpleCalculator Namespace die folgende Klasse hinzu:

<Export(GetType(ICalculator))>
Public Class MySimpleCalculator
   Implements ICalculator

End Class
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{

}

Dieser Export entspricht dem Import in Program. Damit der Export mit dem Import übereinstimmt, muss der Export über denselben Vertrag verfügen. Beim Export unter einem Vertrag auf Grundlage von typeof(MySimpleCalculator) wäre ein Konflikt die Folge, und der Import würde nicht ausgefüllt werden. Der Vertrag muss genau übereinstimmen.

Da der Kompositionscontainer mit allen in dieser Assembly verfügbaren Teilen aufgefüllt wird, ist der MySimpleCalculator Teil verfügbar. Wenn der Konstruktor eine Komposition am Program-Objekt durchführt, wird dessen Import mit einem Program-Objekt gefüllt, das zu diesem Zweck erstellt wird.

Die Benutzeroberflächenebene (Program) muss nichts anderes wissen. Sie können daher den Rest der Benutzeroberflächenlogik in der Main Methode ausfüllen.

Fügen Sie der Main-Methode folgenden Code hinzu:

Sub Main()
    ' Composition is performed in the constructor.
    Dim p As New Program()
    Dim s As String
    Console.WriteLine("Enter Command:")
    While (True)
        s = Console.ReadLine()
        Console.WriteLine(p.calculator.Calculate(s))
    End While
End Sub
static void Main(string[] args)
{
    // Composition is performed in the constructor.
    var p = new Program();
    Console.WriteLine("Enter Command:");
    while (true)
    {
        string s = Console.ReadLine();
        Console.WriteLine(p.calculator.Calculate(s));
    }
}

Dieser Code liest einfach eine Eingabezeile und ruft die Calculate-Funktion von ICalculator auf das Ergebnis auf, das er wieder in die Konsole schreibt. Das ist der gesamte Code, den Sie in Program benötigen. Der Rest der Arbeiten wird in den einzelnen Teilen durchgeführt.

Importe und ImportMany-Attribute

Damit SimpleCalculator erweiterbar ist, muss eine Liste von Vorgängen importiert werden. Ein gewöhnliches ImportAttribute Attribut wird von einem und nur einem ExportAttributeausgefüllt. Wenn mehrere verfügbar sind, erzeugt das Kompositionsmodul einen Fehler. Um einen Import zu erstellen, der mit einer beliebigen Anzahl von Exporten gefüllt werden kann, können Sie das ImportManyAttribute Attribut verwenden.

Fügen Sie der Klasse die folgende Operations-Eigenschaft hinzu MySimpleCalculator :

<ImportMany()>
Public Property operations As IEnumerable(Of Lazy(Of IOperation, IOperationData))
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;

Lazy<T,TMetadata> ist ein Von MEF bereitgestellter Typ, der indirekte Verweise auf Exporte enthält. Zusätzlich zum exportierten Objekt selbst erhalten Sie auch Exportmetadaten oder Informationen, die das exportierte Objekt beschreiben. Jedes Lazy<T,TMetadata> enthält ein IOperation Objekt, das einen tatsächlichen Vorgang darstellt, und ein IOperationData Objekt, das seine Metadaten darstellt.

Fügen Sie dem Modul oder SimpleCalculator Namespace die folgenden einfachen Schnittstellen hinzu:

Public Interface IOperation
    Function Operate(left As Integer, right As Integer) As Integer
End Interface

Public Interface IOperationData
    ReadOnly Property Symbol As Char
End Interface
public interface IOperation
{
     int Operate(int left, int right);
}

public interface IOperationData
{
    char Symbol { get; }
}

In diesem Fall ist die Metadaten für jeden Vorgang das Symbol, das diesen Vorgang darstellt, z. B. +, -, *usw. Um den Additionsvorgang verfügbar zu machen, fügen Sie die folgende Klasse zum Modul oder SimpleCalculator Namespace hinzu:

<Export(GetType(IOperation))>
<ExportMetadata("Symbol", "+"c)>
Public Class Add
    Implements IOperation

    Public Function Operate(left As Integer, right As Integer) As Integer Implements IOperation.Operate
        Return left + right
    End Function
End Class
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add: IOperation
{
    public int Operate(int left, int right)
    {
        return left + right;
    }
}

Das ExportAttribute Attribut funktioniert wie zuvor. Das ExportMetadataAttribute Attribut fügt Metadaten in Form eines Namenswertpaars an diesen Export an. Während die Add-Klasse IOperation implementiert, wird eine Klasse, die IOperationData implementiert, nicht explizit definiert. Stattdessen wird eine Klasse implizit von MEF mit Eigenschaften basierend auf den Namen der bereitgestellten Metadaten erstellt. (Dies ist eine von mehreren Möglichkeiten, auf Metadaten in MEF zuzugreifen.)

Komposition in MEF ist rekursiv. Sie haben das Program Objekt explizit erstellt, das ein ICalculator objekt importiert hat, das sich als Typ MySimpleCalculatorerwiesen hat. MySimpleCalculator wiederum importiert eine Sammlung von IOperation Objekten, die dann bei der Erstellung von MySimpleCalculator ausgefüllt wird, gleichzeitig mit den Importen von Program. Wenn die Add Klasse einen weiteren Import deklariert hat, müsste dies ebenfalls ausgefüllt werden usw. Alle Importe, die nicht ausgefüllt wurden, führen zu einem Kompositionsfehler. (Es ist jedoch möglich, Importe optional zu deklarieren oder ihnen Standardwerte zuzuweisen.)

Rechnerlogik

Sind diese Teile bereitgestellt, bleibt nun noch die Rechnerlogik selbst. Fügen Sie den folgenden Code in der MySimpleCalculator Klasse hinzu, um die Calculate Methode zu implementieren:

Public Function Calculate(input As String) As String Implements ICalculator.Calculate
    Dim left, right As Integer
    Dim operation As Char
    ' Finds the operator.
    Dim fn = FindFirstNonDigit(input)
    If fn < 0 Then
        Return "Could not parse command."
    End If
    operation = input(fn)
    Try
        ' Separate out the operands.
        left = Integer.Parse(input.Substring(0, fn))
        right = Integer.Parse(input.Substring(fn + 1))
    Catch ex As Exception
        Return "Could not parse command."
    End Try
    For Each i As Lazy(Of IOperation, IOperationData) In operations
        If i.Metadata.symbol = operation Then
            Return i.Value.Operate(left, right).ToString()
        End If
    Next
    Return "Operation not found!"
End Function
public String Calculate(string input)
{
    int left;
    int right;
    char operation;
    // Finds the operator.
    int fn = FindFirstNonDigit(input);
    if (fn < 0) return "Could not parse command.";

    try
    {
        // Separate out the operands.
        left = int.Parse(input.Substring(0, fn));
        right = int.Parse(input.Substring(fn + 1));
    }
    catch
    {
        return "Could not parse command.";
    }

    operation = input[fn];

    foreach (Lazy<IOperation, IOperationData> i in operations)
    {
        if (i.Metadata.Symbol.Equals(operation))
        {
            return i.Value.Operate(left, right).ToString();
        }
    }
    return "Operation Not Found!";
}

Durch die anfänglichen Schritte wird die Eingabezeichenfolge analysiert und in linke und rechte Operanden sowie in ein Operatorzeichen eingeteilt. In der foreach Schleife wird jedes Element der operations Sammlung untersucht. Diese Objekte sind vom Typ Lazy<T,TMetadata>und deren Metadatenwerte und exportiertes Objekt können mit der Metadata Eigenschaft bzw. der Value Eigenschaft zugegriffen werden. Wenn in diesem Fall die Symbol Eigenschaft des IOperationData Objekts als Übereinstimmung erkannt wird, ruft der Rechner die Operate Methode des IOperation Objekts auf und gibt das Ergebnis zurück.

Um den Rechner abzuschließen, benötigen Sie auch eine Hilfsmethode, die die Position des ersten nicht-stelligen Zeichens in einer Zeichenfolge zurückgibt. Fügen Sie der MySimpleCalculator Klasse die folgende Hilfsmethode hinzu:

Private Function FindFirstNonDigit(s As String) As Integer
    For i = 0 To s.Length - 1
        If Not Char.IsDigit(s(i)) Then Return i
    Next
    Return -1
End Function
private int FindFirstNonDigit(string s)
{
    for (int i = 0; i < s.Length; i++)
    {
        if (!char.IsDigit(s[i])) return i;
    }
    return -1;
}

Sie sollten jetzt in der Lage sein, das Projekt zu kompilieren und auszuführen. In Visual Basic müssen Sie sicherstellen, dass Sie Public das Schlüsselwort Module1 hinzugefügt haben. Geben Sie im Konsolenfenster einen Zusatzvorgang ein, z. B. "5+3", und der Rechner gibt die Ergebnisse zurück. Bei jedem anderen Operator erhalten Sie die Meldung „Vorgang nicht gefunden!“.

Erweitern von SimpleCalculator mithilfe einer neuen Klasse

Jetzt, da der Rechner funktioniert, ist das Hinzufügen eines neuen Vorgangs einfach. Fügen Sie dem Modul oder SimpleCalculator Namespace die folgende Klasse hinzu:

<Export(GetType(IOperation))>
<ExportMetadata("Symbol", "-"c)>
Public Class Subtract
    Implements IOperation

    Public Function Operate(left As Integer, right As Integer) As Integer Implements IOperation.Operate
        Return left - right
    End Function
End Class
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : IOperation
{
    public int Operate(int left, int right)
    {
        return left - right;
    }
}

Kompilieren sie das Projekt, und führen Sie es aus. Geben Sie einen Subtraktionsvorgang ein, z. B. "5-3". Der Rechner unterstützt jetzt Subtraktion sowie Addition.

Erweitern von SimpleCalculator mithilfe einer neuen Assembly

Das Hinzufügen von Klassen zum Quellcode ist einfach genug, aber MEF bietet die Möglichkeit, außerhalb der eigenen Quelle einer Anwendung nach Teilen zu suchen. Um dies zu veranschaulichen, müssen Sie SimpleCalculator so ändern, dass sowohl ein Verzeichnis als auch seine eigene Assembly nach Teilen durchsucht werden, indem ein DirectoryCatalog hinzugefügt wird.

Fügen Sie dem SimpleCalculator-Projekt ein neues Verzeichnis hinzu Extensions . Stellen Sie sicher, dass Sie es auf Projektebene und nicht auf Lösungsebene hinzufügen. Fügen Sie dann der Projektmappe mit dem Namen ExtendedOperations ein neues Klassenbibliotheksprojekt hinzu. Das neue Projekt wird in einer separaten Assembly kompiliert.

Öffnen Sie den Projekteigenschaften-Designer für das ExtendedOperations-Projekt, und klicken Sie auf die Registerkarte " Kompilieren " oder " Erstellen ". Ändern Sie den Buildausgabepfad oder Ausgabepfad so, dass er auf das Verzeichnis "Erweiterungen" im Projektverzeichnis "SimpleCalculator" (.) verweist. \SimpleCalculator\Extensions\).

Fügen Sie in Module1.vb oder Program.cs die folgende Zeile zum Program Konstruktor hinzu:

catalog.Catalogs.Add(
    New DirectoryCatalog(
        "C:\SimpleCalculator\SimpleCalculator\Extensions"))
catalog.Catalogs.Add(
    new DirectoryCatalog(
        "C:\\SimpleCalculator\\SimpleCalculator\\Extensions"));

Ersetzen Sie den Beispielpfad durch den Pfad zu Ihrem Erweiterungsverzeichnis. (Dieser absolute Pfad dient nur zum Debuggen. In einer Produktionsanwendung würden Sie einen relativen Pfad verwenden.) Dadurch DirectoryCatalog werden nun alle Teile hinzugefügt, die in allen Assemblys im Erweiterungsverzeichnis zum Kompositionscontainer gefunden werden.

Fügen Sie im ExtendedOperations Projekt Verweise auf SimpleCalculator und System.ComponentModel.Composition. Fügen Sie in der ExtendedOperations Klassendatei eine Imports oder eine using Direktive für System.ComponentModel.Composition. Fügen Sie auch in Visual Basic eine Imports-Anweisung für SimpleCalculator hinzu. Fügen Sie dann der Klassendatei die ExtendedOperations folgende Klasse hinzu:

<Export(GetType(SimpleCalculator.IOperation))>
<ExportMetadata("Symbol", "%"c)>
Public Class Modulo
    Implements IOperation

    Public Function Operate(left As Integer, right As Integer) As Integer Implements IOperation.Operate
        Return left Mod right
    End Function
End Class
[Export(typeof(SimpleCalculator.IOperation))]
[ExportMetadata("Symbol", '%')]
public class Mod : SimpleCalculator.IOperation
{
    public int Operate(int left, int right)
    {
        return left % right;
    }
}

Beachten Sie, dass das Attribut ExportAttribute denselben Typ wie ImportAttribute haben muss, damit der Vertrag übereinstimmen kann.

Kompilieren sie das Projekt, und führen Sie es aus. Testen Sie den neuen MOD (%)-Operator.

Schlussfolgerung

In diesem Thema wurden die grundlegenden Konzepte von MEF behandelt.

  • Teile, Kataloge und der Kompositionscontainer

    Teile und der Kompositionscontainer sind die grundlegenden Bausteine einer MEF-Anwendung. Ein Teil ist ein beliebiges Objekt, das einen Wert importiert oder exportiert, einschließlich sich selbst. Ein Katalog stellt eine Sammlung von Teilen aus einer bestimmten Quelle bereit. Der Kompositionscontainer verwendet die von einem Katalog bereitgestellten Teile, um die Komposition durchzuführen, die Bindung von Importen an Exporte.

  • Importe und Exporte

    Importe und Exporte sind die Art und Weise, wie Komponenten kommunizieren. Bei einem Import spezifiziert die Komponente einen bestimmten Wert oder ein bestimmtes Objekt, und mit einem Export spezifiziert sie die Verfügbarkeit eines bestimmten Wertes. Jeder Import wird anhand seines Vertrags mit einer Reihe von Exporten verglichen.

Nächste Schritte

Informationen zum Herunterladen des vollständigen Codes für dieses Beispiel finden Sie im SimpleCalculator-Beispiel (Visual Basic).

Weitere Informationen und Codebeispiele finden Sie unter Managed Extensibility Framework. Eine Liste der MEF-Typen finden Sie im System.ComponentModel.Composition Namespace.