Métodos de extensão (Visual Basic)

Visual Basic 2008apresenta os métodos de extensão , que permitem aos desenvolvedores adicionar funcionalidade personalizada para tipos de dados que já estejam 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 uma instância de método do tipo existente.

Remarks

Ummétodo de extensãosó pode ser um Subprocedimento ou um Functionprocedimento. Você não pode definir umapropriedadede extensão, o campoou o evento. Tudoos métodos deextensão devem ser marcados com oatributode extensão<Extension()> partir do System.Runtime.CompilerServicesnamespace.

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

Example

Description

O exemplo a seguir define uma Printaextensão para o Stringtipo 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 dométodo de extensãoestá marcada com oatributode extensão<Extension()>. O módulo no qual o método é definido de marcação é opcional, mas cadamétodo de extensãodeve ser marcadas. System.Runtime.CompilerServicesdevem ser importados para acessar oatributode extensão.

Métodos de extensão podem ser declarados dentro de módulos. Normalmente, o módulo no qual ummé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 ométodo de extensãoé importado, se necessário, 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, este tempo definido com dois parâmetros. O primeiro parâmetro, aString, que estabelece que ométodo de extensãoestende 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 pelo envio de um argumento de seqüência de caracteres para punc: example.PrintAndPunctuate(".")

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

Code

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

Comments

Tudo que é necessário ser capaz de executar essas ou semelhante, os métodos de extensão é que eles sejam no escopo. Se o módulo que contém ummétodo de extensãoestá no escopo, ele ficará visível no IntelliSense e pode ser chamado como se fosse um métodode instância comum.

Observe que os métodos são chamados, nenhum argumento é enviada de em para o primeiro parâmetro. Parâmetro aString nas definições de método anterior é limite a example, a instância do String que os chama. O compilador usará example como o argumento enviado para o primeiro parâmetro.

Tipos que podem ser estendidos.

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

  • Classes (tipos de referência)

  • Estruturas (tipos de valor)

  • Interfaces

  • Delegates

  • Argumentos ByRef e ByVal

  • Parâmetros de método de genérico

  • Arrays

Como o primeiro parâmetro Especifica o tipo de dados que ométodo de extensãoestende, 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âmetro .

Métodos de extensão não são considerados na ligação tardia. No exemplo a seguir, a demonstrativoanObject.PrintMe() gera um MissingMemberExceptionexceção, a mesma exceção você veria se o segundo PrintMedefinição demétodo deextensãoforam 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

Best Practices

Os 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 aplicar principalmente para autores de bibliotecas de classe mas eles 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 de instância acessível existir que tem uma assinatura que é compatível com os argumentos da demonstrativode 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 qualquermétodode extensão. Portanto, se um método de instância apropriada é 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 ummétodo de extensãonão pode impedir que outros programadores escrevendo conflitantes métodos de extensão que podem ter precedência sobre a extensãooriginal.

  • Você pode melhorar a robustez colocando os métodos de extensão no seu próprio namespace. Os consumidores de sua biblioteca podem incluir um namespace ou excluí-lo ou selecione entre namespaces, 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 de uma interface. No entanto, se uma classe implementa duas interfaces têm métodos de extensão com a mesma assinatura, nenhummé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, há 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 no-de instância deescopo método tem uma assinatura que é compatível com os argumentos de uma demonstrativode chamada, o método de instância é escolhido em preferência a qualquermétodode extensão. O método de instância tem precedência, mesmo se ométodo de extensãoé uma opção melhor. No exemplo a seguir, ExampleClass contém um método de instância nomeada ExampleMethod que tem um parâmetro do tipo Integer. métodode extensãoExampleMethod 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 ométododo extensão, porque arg1 é Long e é compatível apenas com o Longparâmetro nométodode extensão. A segunda chamada para ExampleMethod tem um Integer argumento, arg2, e ele chama o métodode 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, inverta 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 de Main chama o método do instância 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 a extensão método 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, ummétodo de extensãonão pode substituir um métodode de instância existente. No entanto, quando ummétodo de extensãotem 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, como mostra o 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 é como segue:

Extension method

Instance method

A situação é mais simples com propriedades: Se ummétodo de extensãotem o mesmo nome de uma propriedade da classe que ele estende, ométodo de extensãonão é visível e não pode ser acessado.

Precedência de método de extensão

Quando dois métodos de extensão possuem assinaturas idênticas estão no escopo e acessível, aquele com prioridade mais alta será chamado. Precedência de uma extensão métododo 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óduloatual.

  2. Métodos de extensão definidos dentro de tipos de dados no namespace atual ou qualquer um dos 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 de importações de qualquer tipo no arquivo atual.

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

  5. Os métodos de extensão definidos dentro de qualquer projeto-tipo de nível importa.

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

Se 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 denominado 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 (Visual Basic)

Referência

System.Runtime.CompilerServices

Declaração de Módulo

Atributos (C# e Visual Basic)

ExtensionAttribute

Conceitos

Parâmetros e argumentos de procedimento (Visual Basic)

Parâmetros opcionais (Visual Basic)

Matrizes de parâmetros (Visual Basic)

O Escopo no Visual Basic