Este artigo foi traduzido por máquina.

Cutting Edge

C# 4.0, a palavra-chave dinâmica e o COM

Dino Esposito

Dino EspositoEu cresceu como um desenvolvedor de C/C++ e, principalmente, antes do advento do Microsoft .NET Framework, geralmente chided meus colegas que programados no Visual Basic para o uso de um idioma sem rigidez de tipos.

Houve um tempo quando digitação estática e da programação com rigidez de tipos foram a maneira óbvia de felicidade do software. Mas a alteração de coisas e hoje a comunidade de desenvolvedores do c# – ao que parece quase todos os desenvolvedores de C/C++ anteriores tenham migrado — geralmente se sentir a necessidade de distinta de um modelo de programação muito mais dinâmico. No mês passado, introduzi alguns recursos de programação dinâmica, a Microsoft disponibiliza por meio da Linguagem c# 4. 0 e Visual Studio 2010. Este mês, eu vai investigar mais profundos em alguns cenários relacionados, iniciando com um dos motivos mais atraentes usando c# 4. 0 – fácil de programar com o COM os objetos dentro do .NET Framework.

Fácil acesso a objetos COM

Um objeto é considerado dinâmico quando a sua estrutura e seu comportamento não são totalmente descritos por um tipo estaticamente definido que o compilador sabe por completo. Sem dúvida, a palavra dinâmica parece um pouco genérica nesse contexto, portanto let’s examinar um exemplo simples. Em uma linguagem de script como VBScript, o código a seguir é executado com êxito:

Set word = CreateObject("Word.Application")

A função CreateObject pressupõe que a seqüência de caracteres ele obtém como um argumento é o progID de um objeto de COM registrados. Ele cria uma instância do componente e retorna a sua interface de automação de IDispatch. Os detalhes da interface IDispatch nunca são visíveis no nível de linguagem de script. O que importa é que você pode escrever 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)

Nesse código, crie primeiro uma referência a um componente que automatiza o comportamento do aplicativo Microsoft Office Word subjacente. Em seguida, você tornar visível a janela principal do Word, adiciona um novo documento, escreve algum texto nele e, em seguida, salve o documento em algum lugar. O código é claro, lê e bem, mais importante, funciona muito bem.

O motivo pelo qual isso funciona, no entanto, é devido a um determinado recurso oferecido pelo VBScript — ligação tardia. Ligação atrasada significa que o tipo de um determinado objeto não é conhecido até que o fluxo de execução atinge o objeto. Quando isso acontece, o ambiente de runtime primeiro assegura que o membro invocado no objeto realmente existe e, em seguida, chama-lo. Nenhuma verificação preliminar, mas não se limitando é feita antes que o código é realmente executado.

Como você deve saber, uma linguagem de script como VBScript não tem um compilador. No entanto, o Visual Basic (incluindo a versão do CLR) para anos teve um recurso semelhante. Eu confessar que freqüentemente envied meus colegas do Visual Basic para a sua capacidade de usar mais facilmente os objetos COM — geralmente valiosos blocos de construção de um aplicativo que você precisa para interoperabilidade com, como o Office. Em alguns casos, na verdade, minha equipe acabou escrevendo algumas partes do código de interoperabilidade no Visual Basic, mesmo quando todo o aplicativo estava no c#. Isso deve ser surpreendente? Não é polyglot uma nova fronteira de alcançar de programação?

No Visual Basic, a função CreateObject existe por razões de compatibilidade (seguro). A questão é que linguagens baseadas em .NET Framework foram projetadas com ligação inicial em mente. Interoperabilidade COM é um cenário endereçada pelo .NET Framework, mas nunca especificamente suportados por linguagens com as palavras-chave e as instalações — não até 4. 0 do c#.

C# 4. 0 (e o Visual Basic) tem os recursos de pesquisa dinâmica que indicam atrasado ligação agora é uma prática aprovada para desenvolvedores do .NET Framework. Com pesquisa dinâmica, você pode codificar o acesso aos métodos, propriedades, campos de forma que ignore a verificação ser resolvidos em tempo de execução de tipos estáticos e propriedades do indexador.

C# 4. 0 também permite que parâmetros opcionais ao reconhecer o valor padrão em uma declaração de membro. Isso significa que, quando invocado de um membro com parâmetros opcionais, argumentos opcionais podem ser omitidos. Além disso, os argumentos podem ser passados por nome, bem como pela posição. No final do dia, melhor vinculação COM no c# 4. 0 significa que agora há suporte para alguns recursos comuns de linguagens de script com uma linguagem caso contrário, estática e com rigidez de tipos. Antes de examinarmos como você pode utilizar a nova palavra-chave dinâmica operar perfeitamente com objetos COM, let’s investigar um pouco mais para a mecânica interna da pesquisa do tipo dinâmico.

Tempo de execução de linguagem dinâmico

Quando você declara uma variável como dinâmico no Visual Studio 2010, tem o IntelliSense não em todas as na configuração padrão. Curiosamente, se você instalar uma ferramenta adicional como, por exemplo, ReSharper 5. 0 (jetbrains.com/resharper), você pode obter algumas informações parciais através do IntelliSense sobre o objeto dinâmico. A Figura 1 mostra o código do editor com e sem o ReSharper. A ferramenta apenas lista os membros que parecem ser definidos no tipo dinâmico. No mínimo, o objeto dinâmico é uma instância de System. Object.

image: IntelliSense for a Dynamic Object in Visual Studio 2010, with and Without ReSharper
Figura 1 de IntelliSense para um dinâmico de objetos no Visual Studio 2010, com e sem o ReSharper

Let’s, veja o que acontece quando o compilador encontra o código a seguir (o código é deliberadamente simples para simplificar a compreender os detalhes de implementação):

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

Na segunda linha, o compilador não tenta resolver o símbolo WriteLine, e nenhum aviso ou erro é lançado como aconteceria com um verificador de tipo estático clássico. Como diz respeito a palavra-chave dinâmica, c# é como uma linguagem interpretada aqui. Conseqüentemente, o compilador emite algum código ad hoc, interpretará a expressão onde uma variável dinâmica ou o argumento está envolvido.  O interpretador se baseia na Dynamic Language DLR (Runtime), um componente de novo em folha de maquinaria do .NET Framework. Para usar a terminologia do mais específica, o compilador tem que gerar uma árvore de expressão usando a sintaxe abstrata suportada pelo DLR e passá-lo para as bibliotecas do DLR para processamento. Dentro do DLR, a expressão fornecida com o compilador é encapsulada em um objeto de site atualizado dinamicamente. Um objeto de site é responsável por métodos de vinculação a objetos do sistema em funcionamento. A Figura 2 mostra uma versão corrigida em grande parte do código real emitido para o programa trivial, mostrado anteriormente.

O código de do Figura 2 tenha sido editado e simplificado para melhor legibilidade, mas ele mostra a essência do que está acontecendo no. A variável dinâmica é mapeada para uma instância de System. Object e, em seguida, um site é criado para o programa em que o DLR. O site gerencia uma ligação entre o método WriteLine com seus parâmetros e o objeto de destino. A ligação contém dentro do contexto do tipo de programa. Para chamar o método console. WriteLine em uma variável dinâmica, você chama o site e passar o objeto de destino (nesse caso, o tipo de console) e seus parâmetros (no caso da variável dinâmica). Internamente, o site irá verificar se o objeto de destino tem realmente um membro WriteLine, que pode aceitar um parâmetro como o objeto atualmente armazenado na variável x. Se algo der errado, o runtime do c# emite apenas RuntimeBinderException.

Da implementação real de uma variável dinâmica, a Figura 2

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

Trabalhando com objetos COM

Trabalhando COM objetos de aplicativos baseados no .NET Framework consideravelmente mais fácil hoje em dia novos recursos de Linguagem c# 4. 0. Let’s, veja como criar um documento do Word em c# e compare o código que necessário no .NET 3. 5 e o .NET 4. O aplicativo de exemplo cria um novo documento do Word com base em um determinado modelo, ele se esgota e salva-o em uma localização fixa. O modelo contém alguns dos indicadores de partes comuns de informações. Se o destino de .NET Framework 3. 5 ou o .NET Framework 4, a primeira etapa na forma de criar por programação um documento do Word está adicionando a biblioteca de objetos do Microsoft Word (consulte do Figura 3).

image: Referencing the Word Object Library
De referenciar a biblioteca de objetos do Word, a Figura 3

Antes do Visual Studio 2010 e o .NET Framework 4, para fazer isso é necessário código, como em do Figura 4.

De criar um novo documento do Word no c# 3. 0, a Figura 4

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 interagir com uma interface de automação de COM, você freqüentemente precisa tipos Variant. Quando você interage com um objeto de automação COM do dentro de um aplicativo baseado no .NET Framework, você representar variações como objetos simples. O resultado é que você não pode usar uma seqüência de caracteres para indicar, por exemplo, o nome do arquivo de modelo que você pretende basear o seu documento do Word, porque o parâmetro de tipo Variant que deve ser passado por referência. Você precisa recorrer a um objeto em vez disso, como mostrado aqui:

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

Um segundo aspecto a considerar é que os do Visual Basic e linguagens de script são forgiving muito mais do que o c# 3. 0. Assim, por exemplo, eles Don forçá-lo para especificar todos os parâmetros que declara um método em um objeto COM. O método Add no conjunto de documentos exige quatro argumentos e não é possível ignorá-los, a menos que o seu idioma oferece suporte a parâmetros opcionais.

Como mencionado anteriormente, o c# 4. 0 oferece suporte a parâmetros opcionais. Isso significa que embora apenas recompilar o código de do Figura 4 com c# 4. 0 funcione, você poderia até mesmo reescrevê-la e descartar todos os parâmetros ref que contêm apenas um valor que está faltando, como mostrado aqui:

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

Com a nova Linguagem c# 4. 0 “ omitir ref ” suporte, o código no do Figura 4 se torna ainda mais simples e, mais importante é que ele se torna mais fácil de ler e sintaticamente similar ao código de script. A Figura 5 contém a versão editada que compila bem com c# 4. 0 e produz o mesmo efeito que o código de do Figura 4.

De criar um novo documento do Word no c# 4,0. 0, a Figura 5

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

O código no do Figura 5 permite que você pode usar tipos simples do .NET Framework para fazer a chamada para o objeto COM.Além disso, os parâmetros opcionais torná-lo ainda mais simples.

A palavra-chave dinâmica e outros recursos de interoperabilidade de COM introduzido no c# 4. 0 Don fizer um trecho de código necessariamente mais rápido, mas permite que você escreva código em c# como se fosse o script.Para objetos COM, esta conquista é provavelmente tão importante quanto um incremento de desempenho.

Nenhuma implantação de PIA

Desde o início do .NET Framework, você pode dispor de um objeto COM em uma classe gerenciada e usá-lo a partir de um aplicativo baseado em .net.Para que isso aconteça, você precisa usar o uso de um assembly de interoperabilidade primária (PIA) fornecido pelo fornecedor do COM object.PIAs são necessários e deve ser implantada junto com aplicativos cliente.No entanto, mais freqüentemente do que não seja, PIAs são muito grandes e resumir um inteiro COM API, de modo de remessa-los com o programa de instalação pode não ser uma experiência agradável.

O Visual Studio 2010 oferece a opção de não-PIA.PIA não se refere à capacidade do compilador para incorporar as definições necessárias que obteria a partir de um PIA do conjunto atual.Como resultado, apenas as definições são realmente necessários são encontradas no assembly final e não é necessário para que você compacte PIAs do fornecedor na configuração.Figura 6 mostra a opção na caixa de propriedades permite que o PIA do não no Visual Studio 2010.

image: Enabling the No-PIA Option in Visual Studio 2010
Figura 6 de Ativar a opção de não-PIA no Visual Studio 2010

PIA não se baseia em um recurso do c# 4. 0 conhecido como o tipo de equivalência.Em resumo, tipo de equivalência significa que dois tipos distintos podem ser considerados equivalentes em tempo de execução e usados de forma intercambiável.O exemplo típico de tipo de equivalência é duas interfaces com o mesmo nome definido em diferentes assemblies.Eles são diferentes tipos, mas podem ser usados indiscriminadamente, contanto que os mesmos métodos existem.

Em resumo, trabalhar com objetos COM pode ainda ser cara, mas o suporte para interoperabilidade COM em c# 4. 0 torna muito mais simples de código escrito por você.Lidar com objetos COM de aplicativos baseados no .NET Framework conecta-se a aplicativos herdados e cenários de negócios essenciais através da qual você tivesse pouco controle.COM é um mal necessário no Frameworok do .net, mas dinâmico torna um pouco menos assim.

Dino Esposito* é autor do livro* Programming ASP.NET MVC da Microsoft Press e foi co-autor Microsoft .net: Arquitetura de aplicativos para a empresa(Microsoft Press, 2008). Residente na Itália, Esposito é um palestrante sempre presente em eventos do setor no mundo inteiro. Você pode ingressar em seu blog em weblogs.asp.net/despos.

Graças ao especialista técnico seguir para revisar este artigo: Alex Turner