Dieser Artikel wurde maschinell übersetzt.

Innovationen

C# 4.0, das Schlüsselwort "dynamic" und COM

Dino Esposito

Dino EspositoIch oben vergrößert wurde, als C/C++-Entwickler, und insbesondere vor der Einführung von Microsoft .NET Framework, chided ich häufig meiner Kollegen, die in Visual Basic, programmiert für die Verwendung einer schwach typisierten Sprache.

Es wurde ein bei statischen eingeben und stark typisierte Programmierung die offensichtliche Möglichkeit zum Glück Software waren. Jedoch Aktionen ändern, und heute der C#-Entwickler-Community –, scheint der fast alle früheren C/C++-Entwickler haben migriert – fühlen oft unterschiedliche muss ein wesentlich dynamischere Programmiermodell. Im letzten Monat führte ich einige Features der dynamischen Programmierung, die Microsoft durch c# 4.0 und Visual Studio 2010 verfügbar gemacht. In diesem Monat ich werde genau tiefer in einigen verwandten Szenarien mit einem der überzeugendsten Gründe für die Verwendung von c# 4.0 – leicht Programmieren mit COM-Objekten im .NET Framework.

Einfacher Zugriff auf COM-Objekte

Ein Objekt hat dynamisch sein, wenn Sie dessen Struktur und Verhalten vollständig beschrieben werden nicht durch einen statisch definierten Typ an, die der Compiler, gründlich weiß. Zugegeben, das dynamische Wort in diesem Kontext ein bisschen generische klingt, also let’s betrachten Sie ein einfaches Beispiel. In einer Skriptsprache wie VBScript wird der folgende Code erfolgreich ausgeführt:

Set word = CreateObject("Word.Application")

Die CreateObject-Funktion wird davon ausgegangen, dass die Zeichenfolge abgerufen als Argument der progID eines registrierten COM-Objekts ist. Erstellt eine Instanz der Komponente und gibt dessen IDispatch-Automatisierungsschnittstelle. Die Details der IDispatch-Schnittstelle werden nicht auf der Ebene der Skriptsprache angezeigt. Was ist wichtig ist, dass Sie z.B. Code schreiben können:

Set word = CreateObject("Word.Application")
word.Visible = True
Set doc = word.Documents.Add()
Set selection = word.Selection
selection.TypeText "Hello, world"
selection.TypeParagraph()

doc.SaveAs(fileName)

In diesem Code erstellen Sie zunächst einen Verweis auf eine Komponente, die das Verhalten der Anwendung zugrunde liegende Microsoft Office Word automatisiert. Anschließend im Hauptfenster Word sichtbar machen, fügen Sie ein neues Dokument, Text in diese schreiben und dann das Dokument an einem anderen Ort speichern. Der Code ist klar, liest auch und, noch wichtiger, gut funktioniert.

Der Grund, warum dies, allerdings funktioniert wird durch eine bestimmte Funktion von VBScript angeboten – spätes Binden. Spätes Binden bedeutet, dass der Typ eines bestimmten Objekts bekannt ist nicht, bis der Ausführungsablauf des Objekts aufruft. In diesem Fall gewährleistet die Laufzeitumgebung zunächst, dass der Member für das Objekt aufgerufen wirklich vorhanden ist, und Sie dann ruft. Keine vorläufige Überprüfung überhaupt erfolgt, bevor der Code tatsächlich ausgeführt wird.

Wie Sie wissen vielleicht, wird ein Compilerfehler eine Skriptsprache wie VBScript nicht zugewiesen werden. Visual Basic (einschließlich der CLR-Version) für die Jahre mussten jedoch ein ähnliches Feature. Ich confess ich häufig envied meiner Kollegen für Visual Basic für Ihre Fähigkeit, COM-Objekte leichter zu verwenden – oft wertvollen Bausteine einer Anwendung Sie müssen an, wie z. B. Office-Interop. In einigen Fällen jetzt in der Tat mein Team einige Teile des Interop-Code in Visual Basic schreiben, auch wenn die gesamte Anwendung in c# wurde. Sollte dies überrascht sein? Programmieren finden Sie nicht Polyglot zum Erreichen einer neuen Neuland?

In Visual Basic vorhanden ist aus Gründen der Kompatibilität (sichere) die CreateObject-Funktion. Der Punkt ist, dass bei der frühen Bindung Beachten Sie .NET Framework-basierten Sprachen entwickelt wurden. COM-Interoperabilität ist ein Szenario behandelt, die von .NET Framework jedoch nie speziell von Sprachen mit Stichwörtern und Einrichtungen unterstützt – erst c# 4.0.

C# 4.0 (und in Visual Basic) verfügt über die dynamische Suche-Funktionen, die späte Bindung ist jetzt einer genehmigten Übungen für Entwickler, die .NET Framework. Mit dynamischen Suche können Sie den Zugriff auf die Methoden, Eigenschaften, Indexer-Eigenschaften und Felder in einer Weise, die statische Typüberprüfung zur Laufzeit aufgelöst werden umgeht schreiben.

C# 4.0 ermöglicht auch optionale Parameter durch Standardwert in einer Memberdeklaration erkennen. Dies bedeutet, dass optionale Argumente wird ein Element mit optionalen Parametern aufgerufen, ausgelassen werden soll, wenn können. Darüber hinaus können Argumente über den Namen als auch über die Position übergeben werden. Verbesserte COM-Bindung in c# 4.0 bedeutet einfach am Ende des Tages, dass einige allgemeinen Funktionen von Skriptsprachen jetzt von einer ansonsten statische und stark typisierte Sprache unterstützt werden. Bevor wir herauszufinden, wie Sie das Schlüsselwort new dynamische nahtlos mit COM-Objekten verwendet werden, nutzen können, let’s behandelt etwas tiefer in die interne Funktionsweise des dynamischen Typ Nachschlagen.

Dynamic Language Runtime

Wenn Sie eine Variable als dynamisch in Visual Studio 2010 deklarieren, haben Sie keine IntelliSense überhaupt in der Standardkonfiguration. Interessanterweise können Sie ein zusätzliches Tool z. B. ReSharper 5.0 (jetbrains.com/resharper) installiert haben, Sie einige unvollständige Informationen über IntelliSense über dynamisches Objekt abrufen. Abbildung 1 zeigt den Code-Editor mit und ohne ReSharper. Das Tool Listet nur die Elemente, die für den dynamischen Typ definieren, angezeigt werden. Zumindest ist das dynamische Objekt eine Instanz von System.Object.

image: IntelliSense for a Dynamic Object in Visual Studio 2010, with and Without ReSharper
Abbildung 1 für eine dynamische IntelliSense-Objekt in Visual Studio 2010 mit und ohne ReSharper

Let’s zu sehen, was geschieht, wenn der Compiler den folgenden Code trifft (der Code ist absichtlich einfach zur Vereinfachung der Einzelheiten die Implementierung verstehen):

class Program
{
  static void Main(string[] args) 
  { 
    dynamic x = 1;
    Console.WriteLine(x);
  }
}

In der zweiten Zeile der Compiler zum Auflösen des Symbols WriteLine versucht nicht, und keine Warnungen oder Fehler ausgelöst wie mit eine Prüfung von klassischen statischen Typ geschehen würde. Dynamische Schlüsselwort Bezug ist, gleicht c# hier eine interpretierte Sprache. Daher gibt der Compiler einen ad-hoc-Code, der den Ausdruck interpretiert, wobei eine dynamische Variable oder ein Argument beteiligt ist.  Der Interpreter basiert auf der Dynamic Language Runtime (DLR), eine brandneue Komponente von der .NET Framework-Maschinen. Verwenden Sie spezifischere Begriffe, hat der Compiler generiert eine Ausdrucksbaumstruktur, die mit der abstrakte Syntax, die von der DLR unterstützt und der DLR-Bibliotheken zur Verarbeitung übergeben. In der DLR ist der Compiler bereitgestellter Ausdruck in eine dynamisch aktualisierte Standortobjekt gekapselt. Ein Standortobjekt ist verantwortlich für das Binden von Methoden für Objekte im Handumdrehen. Abbildung 2 zeigt eine weitgehend bereinigte Version der richtigen Code für das einfache Programm zuvor gezeigten ausgegeben.

Bearbeitet der Code in Abbildung 2 und zur besseren Lesbarkeit vereinfacht, aber es zeigt die Gist Vorgänge auf. Dynamische Variable ein System.Object-Instanz zugeordnet ist und eine Website für das Programm in der DLR erstellt. Die Site verwaltet eine Bindung zwischen der WriteLine-Methode mit seiner Parameter und das Zielobjekt. Die Bindung enthält, im Kontext des Typs Programm. Zum Aufrufen der Methode Console.WriteLine auf eine dynamische Variable Aufrufen die Website und das Zielobjekt (in diesem Fall der Console-Typ) und die zugehörigen Parameter (in diesem Fall die dynamische Variable) übergeben. Intern wird die Website überprüft, ob das Zielobjekt wirklich WriteLine-Member hat, der einen Parameter wie das Objekt, das sich momentan in der Variablen X akzeptieren kann. Wenn ein Fehler auftritt, löst die c#-Laufzeitumgebung einfach RuntimeBinderException.

Abbildung 2 die Real-Implementierung einer dynamischen Variablen

internal class Program
{
  private static void Main(string[] args)
  {
    object x = 1;

    if (MainSiteContainer.site1 == null)
    {
      MainSiteContainer.site1 = CallSite<
        Action<CallSite, Type, object>>
        .Create(Binder.InvokeMember(
          "WriteLine", 
          null, 
          typeof(Program), 
          new CSharpArgumentInfo[] { 
            CSharpArgumentInfo.Create(...) 
          }));
    }
    MainSiteContainer.site1.Target.Invoke(
      site1, typeof(Console), x);
  }

  private static class MainSiteContainer
  {
    public static CallSite<Action<CallSite, Type, object>> site1;
  }
}

Arbeiten mit COM-Objekten

Arbeiten mit COM-Objekten aus .NET Framework-basierten Anwendungen erheblich einfacher heute neue C#-4.0-Features. Let’s Informationen zum Erstellen eines Word-Dokuments in c#, und vergleichen Sie den Code in .NET 3.5 und 4 .NET neu. Die Beispielanwendung erstellt ein neues Worddokument auf einer bestimmten Dokumentvorlage basieren, füllt es nach oben und an einen festen Speicherort gespeichert. Die Vorlage enthält eine Reihe von Lesezeichen für allgemeine Angaben. Ob Sie .NET Framework 3.5 oder die .NET Framework-4 abzielen, ist der erste Schritt auf dem Weg zum programmgesteuerten Erstellen eines Word-Dokuments Microsoft Word Object Library hinzufügen (siehe Abbildung 3).

image: Referencing the Word Object Library
Abbildung 3 verweisen auf die Word-Objektbibliothek

Bevor Sie Visual Studio 2010 und die .NET Framework-4 zu diesem Zweck werden Code z. B. in Abbildung 4 erforderlich.

Abbildung 4 Erstellen Sie ein neues Word-Dokument in c# 3.0

public static class WordDocument
{
  public const String TemplateName = @"Sample.dotx";
  public const String CurrentDateBookmark = "CurrentDate";
  public const String SignatureBookmark = "Signature";

  public static void Create(String file, DateTime now, String author)
  {
    // Must be an Object because it is passed as a ref
    Object missingValue = Missing.Value;

    // Run Word and make it visible for demo purposes
    var wordApp = new Application { Visible = true };

    // Create a new document
    Object template = TemplateName;
    var doc = wordApp.Documents.Add(ref template,
      ref missingValue, ref missingValue, ref missingValue);
    doc.Activate();

    // Fill up placeholders in the document
    Object bookmark_CurrentDate = CurrentDateBookmark;
    Object bookmark_Signature = SignatureBookmark;
    doc.Bookmarks.get_Item(ref bookmark_CurrentDate).Range.Select();
    wordApp.Selection.TypeText(current.ToString());
    doc.Bookmarks.get_Item(ref bookmark_Signature).Range.Select();
    wordApp.Selection.TypeText(author);

    // Save the document 
    Object documentName = file;
    doc.SaveAs(ref documentName,
      ref missingValue, ref missingValue, ref missingValue, 
      ref missingValue, ref missingValue, ref missingValue, 
      ref missingValue, ref missingValue, ref missingValue, 
      ref missingValue, ref missingValue, ref missingValue,
      ref missingValue, ref missingValue, ref missingValue);

    doc.Close(ref missingValue, 
      ref missingValue, ref missingValue);
    wordApp.Quit(ref missingValue, 
      ref missingValue, ref missingValue);
  }
}

Für die Interaktion mit COM-Automatisierungsschnittstelle benötigen Sie häufig die Variant-Typen. Wenn Sie mit einem COM-Automatisierung-Objekt aus einer .NET Framework-basierte Anwendung interagieren, darstellen Sie Varianten als einfache Objekte. Der Effekt ist, dass Sie eine Zeichenfolge verwenden können, z. B. den Namen der Vorlagendatei an Ihrem Word-Dokument basieren soll, da Variant-Parameter als Verweis übergeben werden muss. Sie haben zu einem Objekt wie folgt stattdessen zurückgreifen:

Object template = TemplateName;
var doc = wordApp.Documents.Add(ref template,
  ref missingValue, ref missingValue, ref missingValue);

Ein zweiter Aspekt zu berücksichtigen ist, dass Visual Basic und Skriptsprachen sind viel mehr allgemeinere als c# 3.0. Also erzwingen nicht angenommen, Sie Sie alle Parameter an, denen eine Methode eines COM-Objekts deklariert. Die Add-Methode der Documents-Auflistung erfordert vier Argumente, und Sie können nicht ignorieren, sofern Ihre Sprache optionale Parameter unterstützt.

Wie bereits erwähnt, unterstützt c# 4.0 optionale Parameter. Also einfach Kompilieren des Codes in Abbildung 4 mit c# 4.0 funktioniert, zwar Sie könnte sogar schreiben Sie es und alle Ref-Parameter, die nur einen fehlenden Wert, legen wie hier gezeigt:

Object template = TemplateName;
var doc = wordApp.Documents.Add(template);

Mit der neuen c# 4.0 “ unterdrücken Ref ” unterstützt, wird der Code in Abbildung 4 noch einfacher und, noch wichtiger ist es einfacher zu lesen und syntaktisch ähnlich, die Skriptcode wird. Abbildung 5 enthält die bearbeitete Version, die auch mit c# 4.0 kompiliert und erzeugt die gleiche Wirkung wie der Code in Abbildung 4 .

Abbildung 5 Erstellen Sie ein neues Word-Dokument in c# 4,0

public static class WordDocument
{
  public const String TemplateName = @"Sample.dotx";
  public const String CurrentDateBookmark = "CurrentDate";
  public const String SignatureBookmark = "Signature";

  public static void Create(string file, DateTime now, String author)
  {
    // Run Word and make it visible for demo purposes
    dynamic wordApp = new Application { Visible = true };
            
    // Create a new document
    var doc = wordApp.Documents.Add(TemplateName);
    templatedDocument.Activate();

    // Fill the bookmarks in the document
    doc.Bookmarks[CurrentDateBookmark].Range.Select();
    wordApp.Selection.TypeText(current.ToString());
    doc.Bookmarks[SignatureBookmark].Range.Select();
    wordApp.Selection.TypeText(author);

    // Save the document 
    doc.SaveAs(fileName);

    // Clean up
    templatedDocument.Close();
    wordApp.Quit();
  }
}

Der Code in Abbildung 5 können Sie einfache .NET Framework-Typen zu verwenden, um das COM-Objekt aufrufen. Darüber hinaus stellen optionale Parameter es noch einfacher.

Das dynamische Schlüsselwort und andere COM-Interop-Funktionen, die in c# 4.0 eingeführt werden kein Codeabschnitts notwendigerweise schneller vorgenommen, jedoch können Sie C#-Code zu schreiben, als wäre Sie Skript. Bei COM-Objekten ist diese Leistung wahrscheinlich genauso wichtig wie eine Erhöhung der Leistung.

Keine PIA-Bereitstellung

Seit Beginn des .NET Framework, Sie könnte, ein COM-Objekt in einer verwalteten Klasse umschließen und aus einer .NET-basierten Anwendung. Damit dies geschieht müssen Sie eine primäre Interop-Assembly (PIA) mithilfe von vom Hersteller der COM-object.PIAs sind erforderlich und müssen zusammen mit der Client-Anwendungen bereitgestellt werden. Allerdings mehr häufig als nicht primären Interop-Assemblys sind zu groß und Einrichten einer gesamten COM-API wrappen, packen Sie mit dem Setup eine benutzerfreundliche Funktionalität möglicherweise nicht.

Visual Studio 2010 bietet die Option, keine PIA. Keine PIA bezieht sich auf die Compilerfunktion erforderliche Definitionen betten, die Sie eine PIA in der aktuellen Assembly erhalten würden. Daher nur Definitionen, die wirklich benötigt werden, werden in die endgültige Assembly gefunden und besteht keine Notwendigkeit, des Kreditors (PIAs) Ihre Einstellungen zu packen. Abbildung 6 wird durch die Option im Feld Eigenschaften, das in Visual Studio 2010-Nein-PIA ermöglicht.

image: Enabling the No-PIA Option in Visual Studio 2010
Abbildung 6 Aktivieren Sie die Option keine PIA in Visual Studio 2010

Keine PIA basiert auf ein Feature von c# 4.0 als Typ Äquivalenz bezeichnet. Kurz gesagt, heißt Art Äquivalenz, dass zwei unterschiedliche Typen zur Laufzeit als Äquivalent betrachtet und austauschbar verwendet werden können. Das typische Beispiel Typ Äquivalenz ist zwei Schnittstellen mit demselben Namen in unterschiedlichen Assemblys definiert. Sie sind unterschiedliche Typen jedoch austauschbar, solange die gleichen Methoden vorhanden sind.

Zusammenfassend lässt sich sagen arbeiten mit COM-Objekten kann weiterhin teuer sein, aber die COM-Interop-Unterstützung in c# 4.0 geschriebene Code sehr viel einfacher macht. Umgang mit COM-Objekten aus .NET Framework-basierten Anwendungen, die Sie mit älteren Anwendungen und wichtige Geschäftsszenarios, über die Sie sonst nur wenig Kontrolle müssten, verbunden. COM ist eine erforderliche böse in dem .NET Frameworok, jedoch dynamische macht es etwas weniger also.

Dino Esposito ist der Autor von Programmieren von ASP.NET MVC von Microsoft Press und ist MitverfasserMicrosoft .NET: Architecting Applications for the Enterprise (Microsoft Press, 2008). Esposito lebt in Italien und ist ein weltweit gefragter Referent bei Branchenveranstaltungen. Sie finden seinen Blog unter weblogs.asp.net/despos.

Dank an den folgenden technischen Experten für die Überprüfung der in diesem Artikel: Alex Turner