Métodos de extensão (Visual Basic)

Métodos de extensão permitem aos desenvolvedores adicionar funcionalidade personalizada para tipos de dados que já foram definidos sem criar um novo tipo derivado.Métodos de extensão tornam possível escrever um método que pode ser chamado como se fosse um método de instância do tipo existente.

Comentários

Um método de extensão só pode ser um Sub procedimento ou um Function procedimento.Você não pode definir uma propriedade de extensão, o campo ou o evento.Todos os métodos de extensão devem ser marcados com o atributo de extensão <Extension()> partir 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, o método estende.Quando o método é executado, o primeiro parâmetro é vinculado à instância do tipo de dados que invoca o método.

Exemplo

Bb384936.collapse_all(pt-br,VS.110).gifDescrição

O exemplo a seguir define uma Print a extensão para o String tipo de dados.O método usa Console.WriteLine para exibir uma seqüência de caracteres.O parâmetro da Print método, aString, estabelece que o método estende a 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 de marcação é opcional, mas cada método de extensão deve ser marcado.System.Runtime.CompilerServicesdevem 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 no qual um método de extensão é definido não é o mesmo módulo como aquele no qual ele é chamado.Em vez disso, o módulo que contém o método de extensão é importado, se ele precisar ser, para trazê-la para o escopo.Após o módulo que contém Print está no escopo, o método pode ser chamado como se fosse um método de instância comum que leva sem argumentos, como ToUpper:

Module Class1

    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, desta vez definidos com dois parâmetros.O primeiro parâmetro, aString, estabelece que o método de extensão estende String.O segundo parâmetro, punc, tem por objetivo ser uma seqüência de caracteres de pontuação é passada como um argumento quando o método for 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 através do envio de um argumento de seqüência de caracteres para punc:example.PrintAndPunctuate(".")

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

Bb384936.collapse_all(pt-br,VS.110).gifCó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 trazidos 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

Bb384936.collapse_all(pt-br,VS.110).gifComentários

Tudo isso é necessário 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 está no escopo, ele ficará visível no IntelliSense e pode ser chamado como 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 no método anterior definições está vinculado a example, a instância do String que as chama.O compilador usará example como o argumento enviado para o primeiro parâmetro.

Se um método de extensão é chamado para um objeto que é definido como Nothing, o método de extensão é executado.Isso não se aplica aos métodos de instância comum.Você pode verificar explicitamente Nothing no método de extensão.

Tipos que podem ser estendidos

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

  • Classes (tipos de referência)

  • Estruturas (tipos de valor)

  • Interfaces

  • Delegados

  • Argumentos ByRef e ByVal

  • Parâmetros do método genérico

  • Matrizes

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

Métodos de extensão não são considerados na ligação tardia.No exemplo a seguir, a instrução anObject.PrintMe() gera um MissingMemberException exceção, a mesma exceção que você veria se o segundo PrintMe definição de método de extensão foram excluídos.

Option Strict Off
Imports System.Runtime.CompilerServices

Module Module4

    Sub Main()
        Dim aString As String = "Initial value for aString"
        aString.PrintMe()

        Dim anObject As Object = "Initial value for anObject"
        ' The following statement causes a run-time error when Option
        ' Strict is off, and a compiler error when Option Strict is on.
        'anObject.PrintMe()
    End Sub

    <Extension()> 
    Public Sub PrintMe(ByVal str As String)
        Console.WriteLine(str)
    End Sub

    <Extension()> 
    Public Sub PrintMe(ByVal obj As Object)
        Console.WriteLine(obj)
    End Sub

End Module

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 serem considerados.Essas considerações se aplicam principalmente para os autores de bibliotecas de classes, mas elas podem 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ê possui não são mais vulneráveis do que os métodos de extensão adicionados aos tipos que você controle.Algumas coisas que podem ocorrer em classes que você não possui e que podem interferir com os métodos de extensão.

  • Se qualquer membro acessível instância existir que tem uma assinatura que é compatível com os argumentos na instrução de chamada, com nenhuma conversões explicitas de restrição necessárias 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 de extensão existente que dependem de você pode se tornar 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ão ter precedência sobre a extensão original.

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

  • Ele pode ser mais seguro estender interfaces que estender as classes, especialmente se você não possui a interface ou classe.Uma alteração em uma interface afeta cada classe que implementa a ele.Portanto, o autor pode ser menos provável adicionar ou alterar os métodos em uma interface.No entanto, se uma classe implementa duas interfaces que têm os 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 a partir da qual derivam-se muitos outros tipos, existem camadas de possibilidades para a introdução de métodos de instância ou outros métodos de extensão que podem interferir com a sua.

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

Quando um método de instância em escopo tem uma assinatura que é compatível com os argumentos de uma instrução 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 se o método de extensão é uma opção melhor.No exemplo a seguir, ExampleClass contém um método de instância nomeado ExampleMethod que tem um parâmetro do tipo Integer.Método de extensão ExampleMethod estende ExampleClass, e tem um parâmetro do 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 chamada para ExampleMethod no código a seguir chama o método de extensão, pois arg1 é Long e é compatível apenas com o Long parâmetro no método de extensão.A segunda chamada 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

Agora reverte 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

Desta vez – o código em Main chama o método de instância nas duas vezes.Isso ocorre porque ambos 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 pode 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 as assinaturas não entrem em conflito, os dois métodos podem ser acessados.Por exemplo, se classe ExampleClass contém um método chamado ExampleMethod que leva sem argumentos, os métodos de extensão com o mesmo nome mas assinaturas diferentes são permitidas, conforme mostrado no código a seguir.

Imports System.Runtime.CompilerServices

Module Module3

    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

    <Extension()> 
    Sub ExampleMethod(ByVal ec As ExampleClass, 
                  ByVal stringParameter As String)
        Console.WriteLine(stringParameter)
    End Sub

End Module

A saída desse código é o seguinte:

Extension method

Instance method

A situação é mais simples com propriedades: se um método de extensão tiver o mesmo nome de uma propriedade da classe que estende a ele, 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 que tenham assinaturas idênticas estão no escopo e acessível, aquele com prioridade mais alta será chamado.Precedência de um método de extensão baseia-se o mecanismo usado para trazer o método para o escopo.A lista a seguir mostra a hierarquia de precedência, em ordem decrescente.

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

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

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

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

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

  6. Métodos de extensão definidos dentro as importações de namespace do nível do 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 a Print método no exemplo anterior é definido em um módulo denominado StringExtensions, o nome totalmente qualificado é StringExtensions.Print(example) em vez de example.Print().

Consulte também

Referência

System.Runtime.CompilerServices

Declaração do módulo

Atributos (C# e Visual Basic)

ExtensionAttribute

Conceitos

Parâmetros de procedimentos e argumentos (Visual Basic)

Parâmetros opcionais (Visual Basic)

Matrizes de parâmetros (Visual Basic)

Escopo em Visual Basic