Métodos de extensão (Visual Basic)

Visual Basic 2008 apresenta os métodos de extensão, que permitem aos desenvolvedores adicionar funcionalidade personalizada aos tipos de dados que já são definidos sem criar um novo tipo derivado. Métodos de extensão tornam possível escrever um método que pode ser chamado sistema autônomo se fosse um método de instância de tipo existente.

Comentários

Um método de extensão pode ser apenas um Sub procedimento ou uma Function procedimento. Não é possível definir uma propriedade de extensão, campo ou evento.Todos os métodos de extensão devem ser marcados com o atributo de extensão <Extension()> do System.Runtime.CompilerServices espaço para nome.

O primeiro parâmetro em uma definição de método de extensão Especifica o tipo de dados amplia o método.Quando o método for executado, o primeiro parâmetro é limite à instância do tipo de dados que invoca o método.

Exemplo

Descrição

O exemplo a seguir define um Print extensão para o String tipo de dados. O método usará Console.WriteLine Para exibir uma seqüência de caracteres. O parâmetro do Print método, aString, estabelece que o método amplia o String classe.

Imports System.Runtime.CompilerServices

Module StringExtensions

    <Extension()> _
    Public Sub Print(ByVal aString As String)
        Console.WriteLine(aString)
    End Sub

End Module

Observe que a definição do método de extensão está marcada com o atributo de extensão <Extension()>. O módulo no qual o método é definido da marcação é opcional, mas cada método de extensão deve ser marcado.System.Runtime.CompilerServices devem ser importados para acessar o atributo de extensão.

Métodos de extensão podem ser declarados dentro de módulos.Normalmente, o módulo em que é definido um método de extensão não é o mesmo módulo em que ele é chamado.Em vez disso, o módulo que contém o método de extensão é importado, se ele precisar ser, para colocá-lo para o escopo.Após o módulo que contém Print está no escopo, o método pode ser chamado sistema autônomo se fosse um método de instância comum que não requer argumentos, sistema autônomo ToUpper:

Imports ConsoleApplication2.StringExtensions

Module Module1

    Sub Main()

        Dim example As String = "Hello"
        ' Call to extension method Print.
        example.Print()

        ' Call to instance method ToUpper.
        example.ToUpper()
        example.ToUpper.Print()

    End Sub

End Module

O próximo exemplo, PrintAndPunctuate, também é uma extensão do String, esse time definido com dois parâmetros. O primeiro parâmetro, aString, estabelece que estende o método de extensão String. O segundo parâmetro, punc, tem por objetivo ser uma seqüência de caracteres de pontuação que é passada sistema autônomo um argumento quando o método é chamado. O método exibe a seqüência de caracteres seguida por sinais de pontuação.

<Extension()> _
Public Sub PrintAndPunctuate(ByVal aString As String, _
                             ByVal punc As String)
    Console.WriteLine(aString & punc)
End Sub

O método é chamado pelo envio de um argumento de seqüência de caracteres punc: example.PrintAndPunctuate(".")

O exemplo a seguir mostra Print e PrintAndPunctuate definido e denominado. System.Runtime.CompilerServices é importado no módulo de definição para habilitar o acesso ao atributo de extensão.

Código

Imports System.Runtime.CompilerServices

Module StringExtensions

    <Extension()> _
    Public Sub Print(ByVal aString As String)
        Console.WriteLine(aString)
    End Sub

    <Extension()> _
    Public Sub PrintAndPunctuate(ByVal aString As String, _
                                 ByVal punc As String)
        Console.WriteLine(aString & punc)
    End Sub

End Module

Em seguida, os métodos de extensão são transferidos para o escopo e chamados.

Imports ConsoleApplication2.StringExtensions
Module Module1

    Sub Main()

        Dim example As String = "Example string"
        example.Print()

        example = "Hello"
        example.PrintAndPunctuate(".")
        example.PrintAndPunctuate("!!!!")

    End Sub
End Module

Comentários

Tudo isso é necessário para ser capaz de executar essas ou métodos de extensão semelhante é que eles sejam no escopo.Se o módulo que contém um método de extensão estiver no escopo, é visível no IntelliSense e pode ser chamado sistema autônomo se fosse um método de instância comum.

Observe que quando os métodos são invocados, nenhum argumento é enviado em para o primeiro parâmetro.Parâmetro aString nas definições de método anterior estão vinculadas example, a instância do String que chama. O compilador usará example sistema autônomo o argumento enviado para o primeiro parâmetro.

Tipos que podem ser estendidos

Você pode definir um método de extensão em maioria dos tipos que podem ser representadas em uma lista de parâmetros do Visual Basic, incluindo o seguinte:

  • Classes (tipos de referência)

  • Estruturas (tipos de valor)

  • Interfaces

  • Delegados

  • Argumentos ByRef e ByVal

  • Parâmetros de método genérico

  • Matrizes

Porque o primeiro parâmetro especifica o tipo de dados que estende o método de extensão, é necessário e não pode ser opcional.Por esse motivo, Optional parâmetros e ParamArray parâmetros não pode ser o primeiro parâmetro na lista de parâmetros.

Práticas recomendadas

Métodos de extensão fornecem uma maneira conveniente e eficiente para estender um tipo existente.No entanto, para usá-los com sucesso, há alguns pontos a considerar.Essas considerações se aplicam principalmente para os autores de classe bibliotecas, mas pode afetar qualquer aplicativo que usa os métodos de extensão.

Mais geralmente, os métodos de extensão que você adicionar a tipos que você não possui são mais vulneráveis que adicionado a tipos que você controle os métodos de extensão.Algumas coisas que podem ocorrer em classes, você não possui que podem interferir nos métodos de extensão.

  • Se houver qualquer membro de instância acessível que possui uma assinatura é compatível com os argumentos na demonstrativo de chamada, com nenhuma conversão de restrição necessária do argumento para o parâmetro, será usado o método de instância em preferência a qualquer método de extensão.Portanto, se um método de instância apropriado é adicionado a uma classe em algum momento, um membro existente de extensão que dependem de você pode ficar inacessível.

  • O autor de um método de extensão não poderão impedir que outros programadores escrevendo conflitantes métodos de extensão que poderá ter precedência sobre a extensão original.

  • Você pode melhorar a robustez colocando os métodos de extensão no seu próprio namespace.Consumidores de sua biblioteca podem incluir um espaço para nome ou excluí-lo ou selecionar entre espaços para nome separadamente do restante da biblioteca.

  • Pode ser mais seguro estender as interfaces que estender classes, especialmente se você não tem interface ou classe.Uma alterar em uma interface afeta todas as classes que a implementa.Por isso, o autor pode ser menos possibilidade de adicionar ou alterar os métodos em uma interface.No entanto, se uma classe implementa duas interfaces com métodos de extensão com a mesma assinatura, nenhum método de extensão é visível.

  • Estenda o tipo mais específico que você pode.Em uma hierarquia de tipos, se você selecionar um tipo em que muitos outros tipos são derivados, há camadas de possibilidades para a introdução de métodos de instância ou outros métodos de extensão que podem interferir na sua.

Propriedades, métodos de instância e métodos de extensão

Quando um método de instância no escopo tem uma assinatura compatível com os argumentos de uma demonstrativo de chamada, o método de instância é escolhido em preferência a qualquer método de extensão.O método de instância tem precedência, mesmo que o método de extensão é uma correspondência melhor.No exemplo a seguir, ExampleClass contém um método de instância nomeado ExampleMethod que tem um parâmetro de tipo Integer. Método de extensão ExampleMethod amplia ExampleClass, e tem um parâmetro de tipo Long.

Class ExampleClass
    ' Define an instance method named ExampleMethod.
    Public Sub ExampleMethod(ByVal m As Integer)
        Console.WriteLine("Instance method")
    End Sub
End Class

<Extension()> _
Sub ExampleMethod(ByVal ec As ExampleClass, _
                  ByVal n As Long)
    Console.WriteLine("Extension method")
End Sub

A primeira telefonar para ExampleMethod o código a seguir chama o método de extensão, porque arg1 é Long e é compatível somente com o Long parâmetro no método de extensão. A segunda telefonar para ExampleMethod tem um Integer argumento, arg2, e chama o método de instância.

Sub Main()
    Dim example As New ExampleClass
    Dim arg1 As Long = 10
    Dim arg2 As Integer = 5

    ' The following statement calls the extension method.
    example.ExampleMethod(arg1)
    ' The following statement calls the instance method.
    example.ExampleMethod(arg2)
End Sub

Reverte agora os tipos de dados dos parâmetros nos dois métodos:

Class ExampleClass
    ' Define an instance method named ExampleMethod.
    Public Sub ExampleMethod(ByVal m As Long)
        Console.WriteLine("Instance method")
    End Sub
End Class

<Extension()> _
    Sub ExampleMethod(ByVal ec As ExampleClass, _
                      ByVal n As Integer)
        Console.WriteLine("Extension method")
    End Sub

Dessa vez o código em Main chama o método de instância nas duas vezes. Isso ocorre porque os dois arg1 e arg2 ter uma conversação para Long, e o método de instância tem precedência sobre o método de extensão em ambos os casos.

Sub Main()
    Dim example As New ExampleClass
    Dim arg1 As Long = 10
    Dim arg2 As Integer = 5

    ' The following statement calls the instance method.
    example.ExampleMethod(arg1)
    ' The following statement calls the instance method.
    example.ExampleMethod(arg2)
End Sub

Portanto, um método de extensão não é possível substituir um método de instância existentes.No entanto, quando um método de extensão tem o mesmo nome de um método de instância, mas sistema autônomo assinaturas não entrem em conflito, são sistema autônomo dois métodos pode ser acessado.Por exemplo, se de classeExampleClass contém um método chamado ExampleMethod que leva sem argumentos, métodos de extensão com o mesmo nome mas assinaturas diferentes são permitidas, sistema autônomo mostra o código a seguir.

Imports ConsoleApplication2.ExtensionExample
Module Module1

    Sub Main()
        Dim ex As New ExampleClass
        ' The following statement calls the extension method.
        ex.ExampleMethod("Extension method")
        ' The following statement calls the instance method.
        ex.ExampleMethod()
    End Sub

    Class ExampleClass
        ' Define an instance method named ExampleMethod.
        Public Sub ExampleMethod()
            Console.WriteLine("Instance method")
        End Sub
    End Class

End Module
Imports System.Runtime.CompilerServices

' Define an extension method named ExampleMethod.
Module ExtensionExample
    <Extension()> _
    Sub ExampleMethod(ByVal ec As ExampleClass, _
                      ByVal stringParameter As String)
        Console.WriteLine(stringParameter)
    End Sub

End Module

A saída desse código é sistema autônomo segue:

Extension method

Instance method

A situação é mais simples com propriedades: Se um método de extensão tem o mesmo nome sistema autônomo uma propriedade da classe aumenta, o método de extensão não estiver visível e não pode ser acessado.

Precedência de método de extensão

Quando dois métodos de extensão com assinaturas idênticas no escopo e acessível, aquele com prioridade mais alta será chamado.Precedência de um método de extensão se baseia o mecanismo usado para trazer o método para o escopo.A lista a seguir mostra a hierarquia de precedência, da mais alta para a mais baixa.

  1. Métodos de extensão definidos dentro do módulo corrente.

  2. Os métodos de extensão definidos dentro de dados tipos no namespace corrente ou em qualquer um de seus pais, com espaços para nomes do filho ter precedência maior do que espaços para nome pai.

  3. Métodos de extensão definidos dentro de qualquer tipo de importações no arquivo corrente.

  4. Métodos de extensão definidos dentro de qualquer importações de namespace no arquivo corrente.

  5. Métodos de extensão definidos dentro de qualquer tipo de nível de projeto imports.

  6. Métodos de extensão definidos dentro de qualquer importações de namespace de nível de projeto.

Se a precedência não resolver a ambigüidade, você pode usar o nome totalmente qualificado para especificar o método que você está chamando.Se o Print método no exemplo anterior é definido em um módulo nomeado StringExtensions, o nome totalmente qualificado é StringExtensions.Print(example) em vez de example.Print().

Consulte também

Tarefas

Como: Definir parâmetros opcionais para um procedimento

Conceitos

Aplicação de Atributos

Parâmetros do procedimento e argumentos

Parâmetros Opcionais

Matrizes de parâmetro

Visão Geral de Atributos em Visual Basic

O Escopo no Visual Basic

Referência

System.Runtime.CompilerServices

Declaração de Módulo

ExtensionAttribute