Exemplarische Vorgehensweise: Einbetten von Typen verwalteter Assemblys in Visual Studio

Wenn Sie Typinformationen von einer verwalteten Assembly mit starkem Namen einbetten, können Sie Typen in einer Anwendung lose koppeln, um versionsunabhängig zu werden. Das heißt, Ihr Programm kann so geschrieben werden, dass Typen aus einer beliebigen Version einer verwalteten Bibliothek verwendet werden, ohne dass es für jede neue Version neu kompiliert werden muss.

Das Einbetten von Typen wird häufig mit COM-Interop verwendet, z.B. mit einer Anwendung, die Automatisierungsobjekte von Microsoft Office verwendet. Das Einbetten von Typinformationen lässt zu, dass derselbe Build eines Programms mit unterschiedlichen Versionen von Microsoft Office auf verschiedenen Computern verwendet werden kann. Allerdings können Sie die Typeinbettung mit vollständig verwalteten Lösungen verwenden.

Nachdem Sie die öffentlichen Schnittstellen angegeben haben, die eingebettet werden können, können Sie Laufzeitklassen erstellen, die diese Schnittstellen implementieren. Ein Clientprogramm kann die Typinformationen für die Schnittstellen zur Entwurfszeit einbetten, indem auf die Assembly verwiesen wird, die die öffentlichen Schnittstellen enthält und die Eigenschaft Embed Interop Types des Verweises auf True festgelegt wird. Das Clientprogramm kann dann Instanzen Ihrer Laufzeitobjekte laden, die als diese Schnittstellen typisiert sind. Dies entspricht dem Verwenden des Befehlszeilencompilers und dem Verweisen auf die Assembly mit der EmbedInteropTypes-Compileroption.

Wenn Sie eine neue Version Ihrer Runtimeassembly mit starkem Namen erstellen, muss das Clientprogramm nicht neu kompiliert werden. Das Clientprogramm verwendet weiterhin die verfügbare Version der Runtimeassembly und die eingebetteten Typinformationen für die öffentlichen Schnittstellen.

In dieser exemplarischen Vorgehensweise:

  1. Erstellen Sie eine Assembly mit starkem Namen mit einer öffentlichen Schnittstelle, die Typinformationen enthält, die eingebettet werden können.
  2. Erstellen Sie eine Runtimeassembly mit starkem Namen, die diese öffentliche Schnittstelle implementiert.
  3. Erstellen Sie ein Clientprogramm, das die Typinformationen aus der öffentlichen Schnittstelle einbettet und eine Instanz der Klasse aus der Runtime-Assembly erstellt.
  4. Ändern Sie die Runtime-Assembly, und erstellen Sie sie erneut.
  5. Führen Sie das Clientprogramm aus, um zu überprüfen, dass es die neue Version der Runtimeassembly verwendet, ohne eine erneute Kompilierung zu erfordern.

Hinweis

Auf Ihrem Computer werden möglicherweise andere Namen oder Speicherorte für die Benutzeroberflächenelemente von Visual Studio angezeigt als die in den folgenden Anweisungen aufgeführten. Diese Elemente sind von der jeweiligen Visual Studio-Version und den verwendeten Einstellungen abhängig. Weitere Informationen finden Sie unter Personalisieren der IDE.

Bedingungen und Einschränkungen

Sie können Typinformationen einer Assembly unter folgenden Bedingungen einbetten:

  • Die Assembly macht mindestens eine öffentliche Schnittstelle verfügbar.
  • Die eingebetteten Schnittstellen werden mit ComImport- und Guid-Attributen mit eindeutigen GUIDs versehen.
  • Die Assembly wird mit dem ImportedFromTypeLib-Attribut oder dem PrimaryInteropAssembly-Attribut und einem Guid-Attribut auf Assemblyebene kommentiert. Die Visual C#- und Visual Basic-Projektvorlagen enthalten standardmäßig ein Guid-Attribut auf Assemblyebene.

Da die primäre Funktion der Typeinbettung in der Unterstützung von COM-Interop-Assemblys besteht, gelten die folgenden Einschränkungen, wenn Sie Typinformationen in eine vollständig verwaltete Lösung einbetten:

  • Nur die für COM-Interop spezifischen Attribute werden eingebettet. Andere Attribute werden ignoriert.
  • Wenn ein Typ generische Parameter verwendet, und der Typ des generischen Parameters ein eingebetteter Typ ist, kann dieser Typ nicht über die Grenze einer Assembly hinaus verwendet werden. Beispiele für das Überschreiten der Grenze einer Assembly umfassen das Aufrufen einer Methode von einer anderen Assembly aus oder das Ableiten eines Typs von einem Typ, der in einer anderen Assembly definiert wurde.
  • Konstanten werden nicht eingebettet.
  • Die System.Collections.Generic.Dictionary<TKey,TValue>-Klasse unterstützt keinen eingebetteten Typ als Schlüssel. Sie können Ihren eigenen Wörterbuchtyp implementieren, um einen eingebetteten Typ als Schlüssel zu unterstützen.

Erstellen einer Schnittstelle

Der erste Schritt besteht darin, die Schnittstellenassembly mit Typäquivalenz zu erstellen.

  1. Klicken Sie in Visual Studio auf Datei>Neu>Projekt.

  2. Geben Sie Klassenbibliothek im Feld Nach Vorlagen suchen des Dialogfelds Neues Projekt erstellen ein. Wählen Sie die Vorlage Klassenbibliothek (.NET Framework) für C# oder Visual Basic aus der Liste aus, und klicken Sie dann auf Weiter.

  3. Geben Sie TypeEquivalenceInterface im Dialogfeld Neues Projekt konfigurieren unter Projektname ein, und klicken Sie dann auf Erstellen. Das neue Projekt wird erstellt.

  4. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Datei Class1.cs oder Class1.vb, wählen Sie Umbenennen aus, und benennen Sie die Datei Class1 in ISampleInterface um. Wählen Sie bei der Eingabeaufforderung Ja aus, um auch die Klasse in ISampleInterface umzubenennen. Diese Klasse stellt die öffentliche Schnittstelle für die Klasse dar.

  5. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceInterface, und wählen Sie dann Eigenschaften aus.

  6. Klicken Sie im linken Bereich der Eigenschaften auf Erstellen, und legen Sie einen Speicherort auf Ihrem Computer als Ausgabepfad fest, z. B. C:\TypeEquivalenceSample. Diesen Speicherort werden Sie im Rahmen dieser exemplarischen Vorgehensweise häufiger verwenden.

  7. Wählen Sie im linken Bereich des Bildschirms Eigenschaften die Option Erstellen>Starke Namen aus, und aktivieren Sie dann das Kontrollkästchen Assembly signieren. Wählen Sie in der Schlüsseldatei mit starkem Namen die Option Durchsuchen aus.

  8. Navigieren Sie zu der Datei key.snk, die Sie im TypeEquivalenceInterface-Projekt erstellt haben, wählen Sie sie aus, und wählen Sie dann OK aus. Weitere Informationen finden Sie unter Erstellen eines Paars aus öffentlichem und privatem Schlüssel.

  9. Öffnen Sie die Klassendatei ISampleInterface im Code-Editor, und ersetzen Sie ihren Inhalt durch den folgenden Code, um die ISampleInterface-Schnittstelle zu erstellen:

    using System;
    using System.Runtime.InteropServices;
    
    namespace TypeEquivalenceInterface
    {
        [ComImport]
        [Guid("8DA56996-A151-4136-B474-32784559F6DF")]
        public interface ISampleInterface
        {
            void GetUserInput();
            string UserInput { get; }
        }
    }
    
    Imports System.Runtime.InteropServices
    
    <ComImport()>
    <Guid("8DA56996-A151-4136-B474-32784559F6DF")>
    Public Interface ISampleInterface
        Sub GetUserInput()
        ReadOnly Property UserInput As String
    End Interface
    
  10. Klicken Sie im Menü Extras auf GUID erstellen, und wählen Sie dann im Dialogfeld GUID erstellen das Registrierungsformat aus. Klicken Sie auf Kopieren und dann auf Beenden.

  11. Ersetzen Sie die Beispiel-GUID im Guid-Attribut Ihres Codes durch die kopierte GUID, und entfernen Sie die Klammern ( { } ).

  12. Erweitern Sie den Ordner Eigenschaften im Projektmappen-Explorer, und wählen Sie die Datei AssemblyInfo.cs oder AssemblyInfo.vb aus. Fügen Sie das folgende Attribut im Code-Editor zur Datei hinzu:

    [assembly: ImportedFromTypeLib("")]
    
    <Assembly: ImportedFromTypeLib("")>
    
  13. Klicken Sie auf Datei>Alle speichern, oder drücken Sie STRG+UMSCHALT+S, um die Dateien und das Projekt zu speichern.

  14. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceInterface, und wählen Sie dann Erstellen aus. Die DLL-Datei der Klassenbibliothek wird kompiliert und im angegebenen Buildausgabepfad gespeichert, z. B. C:\TypeEquivalenceSample.

Erstellen einer Laufzeitklasse

Als Nächstes erstellen Sie die Lauftzeitklasse für die Typäquivalenz.

  1. Klicken Sie in Visual Studio auf Datei>Neu>Projekt.

  2. Geben Sie Klassenbibliothek im Feld Nach Vorlagen suchen des Dialogfelds Neues Projekt erstellen ein. Wählen Sie die Vorlage Klassenbibliothek (.NET Framework) für C# oder Visual Basic aus der Liste aus, und klicken Sie dann auf Weiter.

  3. Geben Sie TypeEquivalenceRuntime unter Projektname im Dialogfeld Neues Projekt konfigurieren ein, und klicken Sie dann auf Erstellen. Das neue Projekt wird erstellt.

  4. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Datei Class1.cs oder Class1.vb, wählen Sie Umbenennen aus, und benennen Sie die Datei Class1 in SampleClass um. Wählen Sie bei der Eingabeaufforderung Ja aus, um auch die Klasse in SampleClass umzubenennen. Diese Klasse implementiert die ISampleInterface -Schnittstelle.

  5. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceInterface, und wählen Sie Eigenschaften aus.

  6. Wählen Sie im linken Bereich der Eigenschaften die Option Erstellen aus, und legen Sie dann denselben Speicherort als Ausgabepfad fest, den Sie für das TypeEquivalenceInterface-Projekt verwendet haben, z. B. C:\TypeEquivalenceSample.

  7. Wählen Sie im linken Bereich des Bildschirms Eigenschaften die Option Erstellen>Starke Namen aus, und aktivieren Sie dann das Kontrollkästchen Assembly signieren. Wählen Sie in der Schlüsseldatei mit starkem Namen die Option Durchsuchen aus.

  8. Navigieren Sie zu der Datei key.snk, die Sie im TypeEquivalenceInterface-Projekt erstellt haben, wählen Sie sie aus, und wählen Sie dann OK aus. Weitere Informationen finden Sie unter Erstellen eines Paars aus öffentlichem und privatem Schlüssel.

  9. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceRuntime, und wählen Sie dann Hinzufügen>Verweis aus.

  10. Klicken Sie im Dialogfeld Verweis-Manager auf Durchsuchen, und navigieren Sie zum Ausgabepfadordner. Wählen Sie die Datei TypeEquivalenceInterface.dll aus, und klicken Sie dann auf Hinzufügen und auf OK.

  11. Erweitern Sie im Projektmappen-Explorer den Ordner Verweise, und wählen Sie den Verweis TypeEquivalenceInterface aus. Legen Sie für Spezifische Version im Bereich Eigenschaften die Option FALSE fest, wenn das noch nicht der Fall ist.

  12. Öffnen Sie die Klassendatei SampleClass im Code-Editor, und ersetzen Sie ihren Inhalt durch den folgenden Code, um die SampleClass-Klasse zu erstellen:

    using System;
    using TypeEquivalenceInterface;
    
    namespace TypeEquivalenceRuntime
    {
        public class SampleClass : ISampleInterface
        {
            private string p_UserInput;
            public string UserInput { get { return p_UserInput; } }
    
            public void GetUserInput()
            {
                Console.WriteLine("Please enter a value:");
                p_UserInput = Console.ReadLine();
            }
        }
    }
    
    Imports TypeEquivalenceInterface
    
    Public Class SampleClass
        Implements ISampleInterface
    
        Private p_UserInput As String
        Public ReadOnly Property UserInput() As String Implements ISampleInterface.UserInput
            Get
                Return p_UserInput
            End Get
        End Property
    
        Public Sub GetUserInput() Implements ISampleInterface.GetUserInput
            Console.WriteLine("Please enter a value:")
            p_UserInput = Console.ReadLine()
        End Sub
    End Class
    
  13. Klicken Sie auf Datei>Alle speichern, oder drücken Sie STRG+UMSCHALT+S, um die Dateien und das Projekt zu speichern.

  14. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceRuntime, und wählen Sie dann Erstellen aus. Die DLL-Datei der Klassenbibliothek wird kompiliert und im angegebenen Buildausgabepfad gespeichert.

Erstellen eines Clientprojekts

Schließlich erstellen Sie ein Typäquivalenz-Clientprogramm, das auf die Schnittstellenassembly verweist.

  1. Klicken Sie in Visual Studio auf Datei>Neu>Projekt.

  2. Geben Sie Konsole im Feld Nach Vorlagen suchen des Dialogfelds Neues Projekt erstellen ein. Wählen Sie die Vorlage Konsolen-App (.NET Framework) für C# oder Visual Basic aus der Liste aus, und klicken Sie dann auf Weiter.

  3. Geben Sie TypeEquivalenceClient unter Projektname im Dialogfeld Neues Projekt konfigurieren ein, und klicken Sie dann auf Erstellen. Das neue Projekt wird erstellt.

  4. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceClient, und wählen Sie dann Eigenschaften aus.

  5. Klicken Sie im linken Bereich der Eigenschaften auf Erstellen, und legen Sie dann denselben Speicherort als Ausgabepfad fest, den Sie für das TypeEquivalenceInterface-Projekt verwendet haben, z. B. C:\TypeEquivalenceSample.

  6. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceClient, und wählen Sie dann Hinzufügen>Verweis aus.

  7. Wenn die Datei TypeEquivalenceInterface.dll bereits im Dialogfeld Verweis-Manager aufgeführt wird, wählen Sie sie aus. Wenn nicht, klicken Sie auf Durchsuchen, navigieren Sie zum Ausgabepfadordner, wählen Sie die Datei TypeEquivalenceInterface.dll aus (nicht die Datei TypeEquivalenceRuntime.dll), und klicken Sie schließlich auf Hinzufügen. Klicken Sie auf OK.

  8. Erweitern Sie im Projektmappen-Explorer den Ordner Verweise, und wählen Sie den Verweis TypeEquivalenceInterface aus. Legen Sie für Interoptypen einbetten im Bereich Eigenschaften die Option TRUE fest.

  9. Öffnen Sie die Datei Program.cs oder Module1.vb im Code-Editor, und ersetzen Sie ihren Inhalt durch den folgenden Code, um das Clientprogramm zu erstellen:

    using System;
    using System.Reflection;
    using TypeEquivalenceInterface;
    
    namespace TypeEquivalenceClient
    {
        class Program
        {
            static void Main(string[] args)
            {
                Assembly sampleAssembly = Assembly.Load("TypeEquivalenceRuntime");
                ISampleInterface sampleClass =
                    (ISampleInterface)sampleAssembly.CreateInstance("TypeEquivalenceRuntime.SampleClass");
                sampleClass.GetUserInput();
                Console.WriteLine(sampleClass.UserInput);
                Console.WriteLine(sampleAssembly.GetName().Version.ToString());
                Console.ReadLine();
            }
        }
    }
    
    Imports System.Reflection
    Imports TypeEquivalenceInterface
    
    Module Module1
    
        Sub Main()
            Dim sampleAssembly = Assembly.Load("TypeEquivalenceRuntime")
            Dim sampleClass As ISampleInterface = CType( _
                sampleAssembly.CreateInstance("TypeEquivalenceRuntime.SampleClass"), ISampleInterface)
            sampleClass.GetUserInput()
            Console.WriteLine(sampleClass.UserInput)
            Console.WriteLine(sampleAssembly.GetName().Version)
            Console.ReadLine()
        End Sub
    
    End Module
    
  10. Klicken Sie auf Datei>Alle speichern, oder drücken Sie STRG+UMSCHALT+S, um die Dateien und das Projekt zu speichern.

  11. Drücken Sie STRG+F5, um das Programm zu erstellen und auszuführen. Beachten Sie, dass die Konsolenausgabe die Assemblyversion 1.0.0.0 zurückgibt.

Anpassen der Schnittstelle

Im Folgenden passen Sie de Schnittstellenassembly an und ändern ihre Version.

  1. Klicken Sie in Visual Studio auf Datei>Öffnen>Projekt/Projektmappe, und öffnen Sie das Projekt TypeEquivalenceInterface.

  2. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceInterface, und wählen Sie Eigenschaften aus.

  3. Klicken Sie im linken Bereich der Eigenschaften auf Anwendung, und klicken Sie dann auf Assemblyinformationen.

  4. Ändern Sie die Werte für Assemblyversion und Dateiversion im Dialogfeld Assemblyinformationen in 2.0.0.0, und klicken Sie dann auf OK.

  5. Öffnen Sie die Datei SampleInterface.cs oder SampleInterface.vb, und fügen Sie die folgende Codezeile zur ISampleInterface-Schnittstelle hinzu:

    DateTime GetDate();
    
    Function GetDate() As Date
    
  6. Klicken Sie auf Datei>Alle speichern, oder drücken Sie STRG+UMSCHALT+S, um die Dateien und das Projekt zu speichern.

  7. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceInterface, und wählen Sie dann Erstellen aus. Eine neue Version der DLL-Datei für die Klassenbibliothek wird kompiliert und im Buildausgabepfad gespeichert.

Anpassen der Laufzeitklasse

Ändern Sie außerdem die Laufzeitklasse, und aktualisieren Sie ihre Version.

  1. Klicken Sie in Visual Studio auf Datei>Öffnen>Projekt/Projektmappe, und öffnen Sie das Projekt TypeEquivalenceRuntime.

  2. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceRuntime, und wählen Sie dann Eigenschaften aus.

  3. Klicken Sie im linken Bereich der Eigenschaften auf Anwendung, und klicken Sie dann auf Assemblyinformationen.

  4. Ändern Sie die Werte für Assemblyversion und Dateiversion im Dialogfeld Assemblyinformationen in 2.0.0.0, und klicken Sie dann auf OK.

  5. Öffnen Sie die Datei SampleClass.cs oder SampleClass.vb, und fügen Sie den folgenden Code zur SampleClass-Klasse hinzu:

     public DateTime GetDate()
     {
         return DateTime.Now;
     }
    
    Public Function GetDate() As DateTime Implements ISampleInterface.GetDate
        Return Now
    End Function
    
  6. Klicken Sie auf Datei>Alle speichern, oder drücken Sie STRG+UMSCHALT+S, um die Dateien und das Projekt zu speichern.

  7. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt TypeEquivalenceRuntime, und wählen Sie dann Erstellen aus. Eine neue Version der DLL-Datei für die Klassenbibliothek wird kompiliert und im Buildausgabepfad gespeichert.

Ausführen des aktualisierten Clientprogramms

Öffnen Sie den Speicherort des Buildausgabeordners, und führen Sie die Datei TypeEquivalenceClient.exe aus. Beachten Sie, dass die Konsolenausgabe nun die neue Version der TypeEquivalenceRuntime-Assembly (2.0.0.0) darstellt, ohne dass das Programm neu kompiliert werden musste.

Siehe auch