Este artículo proviene de un motor de traducción automática.

Tecnología de vanguardia

C# 4.0, el teclado dinámico y COM

Dino Esposito

Dino EspositoCreció que un desarrollador de C o C++ y, especialmente antes de la llegada de Microsoft .NET Framework, a menudo chided Mis compañeros que programarán en Visual Basic para el uso de un lenguaje de forma poco segura con tipo.

Se ha producido un tiempo cuando escribe estática y la programación con establecimiento inflexible de tipos eran la manera obvia de felicidad de software.Pero el cambio de las cosas y hoy en día la Comunidad de desarrolladores de C#, para que lo que parece casi todos los desarrolladores de C o C++ antiguos se han migrado, con frecuencia se siente la necesidad de distinta para un modelo de programación mucho más dinámico.El mes pasado presenté algunas de las características de programación dinámico que Microsoft pone a disposición a través de 4.0 de C# y Visual Studio de 2010.Este mes, profundizaremos más en algunos escenarios relacionados, empezando por una de las razones más atractivas para el uso de C# 4.0: fácil de programar con COM objetos dentro de .NET Framework.

Acceso fácil a los objetos COM

Se dice que es un objeto sean dinámicos cuando su estructura y el comportamiento no se describen completamente un tipo definido estáticamente que el compilador conozca exhaustivamente.Hay que reconocer la palabra dinámica suena un poco más genérica en este contexto, por lo tanto, let’s consultar un ejemplo sencillo.En un lenguaje de secuencias de comandos como VBScript, el código siguiente se ejecuta correctamente:

Set word = CreateObject("Word.Application")

La función CreateObject se supone que la cadena obtiene como un argumento es el progID de un objeto COM registrado. Crea una instancia del componente y devuelve su interfaz de automatización IDispatch. Los detalles de la interfaz IDispatch no son visibles en el nivel del lenguaje de secuencias de comandos. Lo que importa es que se puede escribir código como:

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)

En este código, se crea primero una referencia a un componente que automatiza el comportamiento de la aplicación de Microsoft Office Word subyacente. A continuación, se haga visible la ventana principal de Word, agregue un nuevo documento, escribe texto en él y, a continuación, guarde el documento en un lugar. El código está desactivado, se lee bien y, lo más importante, funciona correctamente.

La razón de esto funciona, sin embargo, es debido a una determinada capacidad ofrecida por VBScript: enlace en tiempo de ejecución. Enlace en tiempo de ejecución, significa que el tipo de un objeto especificado es desconocido hasta que el flujo de ejecución encuentra el objeto. En este caso, primero el entorno de tiempo de ejecución garantiza que el miembro invocado en el objeto realmente existe y, a continuación, lo invoca. Antes de que realmente se ejecuta el código, no se realiza ninguna comprobación previa de ningún tipo.

Como ya sabrá, un lenguaje de secuencias de comandos como VBScript no tiene un compilador. Sin embargo, Visual Basic (incluida la versión CLR) para años tenía una característica similar. Confiesa con frecuencia envied mis colegas de Visual Basic por su capacidad utilizar más fácilmente los objetos COM, valiosos con frecuencia bloques de creación de una aplicación que necesita para la interoperabilidad con, como Office. En algunos casos, de hecho, mi equipo terminaba escribir algunas partes de nuestro código de interoperabilidad de Visual Basic, incluso cuando toda la aplicación estaba en C#. ¿Debe tratarse sorprendente? ¿No es polyglot programar una frontera nueva para llegar a?

En Visual Basic, la función CreateObject existe por motivos de compatibilidad (seguras). La cuestión es que los lenguajes basados en .NET Framework se diseñaron con el enlace anticipado en mente. Interoperabilidad COM es un escenario que se solucionan con .NET Framework, pero nunca específicamente compatible con idiomas con palabras clave y las instalaciones, no hasta 4.0 de C#.

C# 4.0 (y Visual Basic) tienen las capacidades de búsqueda dinámicos que se indican en tiempo de ejecución y enlace ahora es una práctica aprobada para que los desarrolladores de .NET Framework. Con la búsqueda dinámica, puede codificar el acceso a los métodos, propiedades, las propiedades del indizador y los campos de forma que omita la comprobación debe resolverse en tiempo de ejecución de tipo estático.

C# 4.0 también permite que los parámetros opcionales al reconocer el valor predeterminado en una declaración de miembro. Esto significa que cuando se invoca un miembro con los parámetros opcionales, se pueden omitir los argumentos opcionales. Además, se pueden pasar argumentos por nombre, así como por posición. Al final del día, mejorado enlace de COM en C# 4.0 significa simplemente que ahora se admiten algunas características comunes de los lenguajes de secuencias de comandos mediante un lenguaje en caso contrario, estático y con establecimiento inflexible. Antes de examinar cómo se puede aprovechar de la palabra clave dinámica nueva puede funcionar perfectamente con los objetos COM, let’s profundizar un poco más en los mecanismos internos de la búsqueda de tipo dinámico.

Dynamic Language Runtime

Cuando se declara una variable como dinámicas en 2010 de Visual Studio, no tiene IntelliSense en absoluto en la configuración predeterminada. Curiosamente, si instala una herramienta adicional como, por ejemplo, ReSharper 5.0 (jetbrains.com/resharper), se puede obtener alguna información parcial a través de IntelliSense, acerca del objeto dinámico. La figura 1 muestra el código con y sin ReSharper de editor. La herramienta sólo enumera a los miembros que parecen estar definido en el tipo dinámico. Como mínimo, el objeto dinámico es una instancia de System.Object.

image: IntelliSense for a Dynamic Object in Visual Studio 2010, with and Without ReSharper
Figura 1 de IntelliSense para una dinámica de objetos en Visual Studio de 2010, con y sin ReSharper

Let’s ver lo que ocurre cuando el compilador encuentra el código siguiente (el código está deliberadamente muy fácil simplificar conocer los detalles de implementación):

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

En la segunda línea, el compilador no intenta resolver el símbolo WriteLine y no se produce ningún error o advertencia tal como sucedería con un corrector clásico de tipo estático. En cuanto a la palabra clave dinámica, C# es similar a un lenguaje interpretado aquí. Por lo tanto, el compilador emite código ad hoc que interpreta la expresión cuando se trate de un argumento o variable dinámica.  El intérprete está basado en el lenguaje dinámico en tiempo de ejecución (DLR), un componente nuevo de la máquina de .NET Framework. Para utilizar terminología más específica, el compilador tiene que generar un árbol de expresión con la sintaxis abstracta compatible con DLR y se pasa a las bibliotecas DLR para su procesamiento. En el DLR, la expresión proporcionada por el compilador se encapsula en un objeto de sitio actualizadas dinámicamente. Un objeto de sitio es responsable de enlazar métodos a los objetos sobre la marcha. La figura 2, se muestra una versión en gran medida limpio del código real emitido para el programa trivial mostrado anteriormente.

El código en de figura 2 se ha modificado y simplificado para facilitar la lectura, pero muestra el fundamental de lo que sucede en. La variable dinámica se asigna a una instancia de System.Object y, a continuación, se crea un sitio para el programa de DLR. El sitio administra un enlace entre el método WriteLine con sus parámetros y el objeto de destino. El enlace se mantiene en el contexto del tipo de programa. Para invocar el método Console.WriteLine en una variable dinámica, se invoca el sitio y se pasan el objeto de destino (en este caso, el tipo de consola) y sus parámetros (en este caso, la variable dinámica). Internamente, el sitio se comprueba si el objeto de destino tiene realmente un miembro WriteLine que acepta un parámetro al igual que el objeto almacenado en la variable x. Si algo va mal, el tiempo de ejecución de C# sólo produce RuntimeBinderException.

La figura 2 de la implementación real de una variable dinámica

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

Trabajar con objetos COM

Nuevas características de C# 4.0 trabajar con objetos COM desde dentro de las aplicaciones basadas en .NET Framework considerablemente más fácil en la actualidad. Let’s, vea cómo crear un documento de Word en C# y comparar el código que necesario en .NET 3.5 y 4. NET. La aplicación de ejemplo crea un nuevo documento de Word que se basa en una plantilla determinada, llena y lo guarda en una ubicación fija. La plantilla contiene un par de marcadores para elementos comunes de información. Si se orienta a .NET Framework 3.5 o el 4 de .NET Framework, el primer paso en la forma de crear mediante programación un documento de Word es agregar la biblioteca de objetos de Microsoft Word (vea de figura 3).

image: Referencing the Word Object Library
La figura 3 de hacer referencia a la biblioteca de objetos de Word

Antes de 2010 de Visual Studio y el 4 de .NET Framework, para ello necesita código, como en de figura 4.

La figura 4 de creación de un documento de Word nuevo en 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);
  }
}

Para interactuar con una interfaz de automatización COM, necesita a menudo los tipos de valor de tipo Variant. Cuando se interactúa con un objeto de automatización COM desde dentro de una aplicación basada en .NET Framework, variantes se representan como objetos sin formato. El resultado final es que no se puede utilizar una cadena para indicar, por ejemplo, el nombre del archivo de plantilla que desea basar un documento de Word, ya que el parámetro de tipo Variant debe pasarse por referencia. Tiene que recurrir a un objeto en su lugar, como se muestra aquí:

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

Un segundo aspecto a tener en cuenta es que los lenguajes de secuencias de comandos de Visual Basic y son mucho más tolerante a C# 3.0. Por lo tanto, por ejemplo, no le obligan a especificar todos los parámetros que se declara un método en un objeto COM. El método Add de la colección Documents requiere cuatro argumentos y no se puede omitir a menos que el lenguaje admite parámetros opcionales.

Como se mencionó anteriormente, C# 4.0 es compatible con los parámetros opcionales. Esto significa que aunque basta con volver a compilar el código en del 4 de la figura con C# 4.0 funciona, podría incluso escribirlo y quite todos los parámetros de referencia que tengan sólo un valor que falta, como se muestra aquí:

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

Con el soporte de “ omitir ref ” de C# 4.0 nuevo, el código en de figura 4 se convierte en aún más sencillo y, lo que es más importante, resulta más fácil de leer y sintácticamente similar al código de secuencias de comandos. La figura 5 contiene la versión modificada de la que se compila correctamente con C# 4.0 y se produce el mismo efecto que el código en de figura 4.

La figura 5 de creación de un documento de Word nuevo en 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();
  }
}

El código en de figura 5 permite utilizar tipos de .NET Framework sin formato para realizar la llamada al objeto COM. Además, los parámetros opcionales que aún más sencillo.

La palabra clave dinámica y otras características de interoperabilidad COM introducidas en C# 4.0 no haga que un fragmento de código necesariamente más rápido, pero permite escribir código de C# como si fuese la secuencia de comandos. Para los objetos COM, este éxito es probablemente es tan importante como un incremento del rendimiento.

No hay implementación de PIA

Desde el inicio de .NET Framework, no se puede ajustar un objeto COM en una clase administrada y utilizarla desde una aplicación basada en. NET. Para que ello, tiene que utilizar con ensamblados de interoperabilidad primarios (PIA) siempre que el proveedor de la COM object.PIAs son necesarios y se debe implementar junto con las aplicaciones de cliente. Sin embargo, más a menudo a no, ensamblados de interoperabilidad primarios son demasiado grandes y resumir una API de COM de todo, por lo que les de empaquetado con el programa de instalación no puede ser una experiencia agradable.

2010 De Visual Studio ofrece la opción de no-PIA. PIA de n hace referencia a la capacidad del compilador para incrustar las definiciones de requiere que obtiene de un PIA en el ensamblado actual. Por tanto, sólo las definiciones que son realmente necesarios se encuentran en el ensamblado final y no es necesario para que se pueden empaquetar ensamblados de interoperabilidad primarios del proveedor en el programa de instalación. La figura 6, se muestra la opción en el cuadro de propiedades que no se permite-PIA en 2010 de Visual Studio.

image: Enabling the No-PIA Option in Visual Studio 2010
La figura 6 de Habilitar la opción N PIA en 2010 de Visual Studio

N-PIA se basa en una función de C# 4.0 que se conoce como tipo de equivalencia. En pocas palabras, la equivalencia de tipo significa que se pueden consideran equivalentes en tiempo de ejecución y utilizar de forma intercambiable dos tipos diferentes. El ejemplo típico de la equivalencia de tipo es de dos interfaces con el mismo nombre definidos en ensamblados diferentes. Son diferentes tipos, pero se pueden utilizar indistintamente los mismos métodos se encuentran.

En resumen, trabajar con objetos COM todavía puede resultar caro, pero la capacidad de interoperabilidad COM en C# 4.0 hace mucho más sencillo el código que escribe. Trabajar con objetos COM desde aplicaciones basadas en .NET Framework conecta a aplicaciones heredadas y los escenarios de negocio críticas que de lo contrario tendría poco control. COM es un mal necesario en el Frameworok. NET, pero dinámicos hace que sea un poco menos así.

Dino Esposito es el autor de Programming ASP.NET MVC de Microsoft Press y coautor de ha .NET de Microsoft: Architecting Applications for the Enterprise (Microsoft Press, 2008). Con residencia en Italia, Esposito participa habitualmente en conferencias y eventos del sector en todo el mundo. Puede participar en su blog en weblogs.asp.net/despos.

Gracias al siguiente experto técnico para este artículo: Alex Turner