lunes, 3 de octubre de 2016

METODO

Los métodos de extensión permiten a los desarrolladores agregar funcionalidad personalizada a los tipos de datos ya definidos sin crear un nuevo tipo derivado.Los métodos de extensión permiten escribir un método al que se puede llamar como si fuera un método de instancia del tipo existente.
Un método de extensión puede ser únicamente un procedimiento Sub o un procedimiento Function.No se puede definir ninguna propiedad, campo o evento de extensión.Todos los métodos de extensión se deben marcar con el atributo de extensión, <Extension()>, del espacio de nombres System.Runtime.CompilerServices.
El primer parámetro de una definición de método de extensión especifica qué tipo de datos extiende el método.Cuando se ejecuta el método, el primer parámetro se enlaza a la instancia del tipo de datos que invoca al método.
Ejemplo
Descripción
En el siguiente ejemplo se define una extensión Print para el tipo de datos String.El método usa Console.WriteLine para mostrar una cadena.El parámetro del método Print, aString, establece que el método de extensión extiende la clase String.
VB
Imports System.Runtime.CompilerServices

Module StringExtensions

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

End Module
Observe que la definición de método de extensión se marca con el atributo de extensión <Extension()>.Marcar el módulo en el que se define el método es opcional, pero se debe marcar cada método de extensión. System.Runtime.CompilerServices debe importarse para poder obtener acceso al atributo de extensión.
Los métodos de extensión se pueden declarar únicamente dentro de los módulos.Normalmente, el módulo en el que se define un método de extensión no es el mismo que el módulo en el que se llama.En su lugar, se importa el módulo que contiene el método de extensión, si fuera necesario, para incluirlo en el ámbito.Después de que el módulo que contiene Print esté en el ámbito, se puede llamar al método como si fuera un método de instancia ordinario que no toma argumentos, como ToUpper:
VB
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
En el ejemplo siguiente, PrintAndPunctuate, también es una extensión de String, esta vez definida con dos parámetros.El primer parámetro, aString, establece que el método de extensión extiende String.El segundo parámetro, punc, está pensado para ser una cadena de signos de puntuación que se pasa como argumento cuando se llama al método.El método muestra la cadena seguida de los signos de puntuación.
VB
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
                             ByVal punc As String)
    Console.WriteLine(aString & punc)
End Sub
Se llama al método enviando un argumento de cadena para punc: example.PrintAndPunctuate(".")
En el siguiente ejemplo, se muestra cómo se definen y se invocan Print y PrintAndPunctuate. System.Runtime.CompilerServices se importa en el módulo de definición para permitir el acceso al atributo de extensión.
Código
VB
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
Después, los métodos de extensión se incluyen en el ámbito y se llaman.
VB
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
Comentarios
Todo esto es necesario para poder ejecutar estos métodos o métodos de extensión similares que están en el ámbito.Si el módulo que contiene un método de extensión está en el ámbito, está visible en IntelliSense y se le llama como si fuera un método de instancia normal.
Observe que cuando se invocan los métodos, no se envía ningún argumento para el primer parámetro.El parámetro, aString en las definiciones de método anteriores, se enlaza a example, la instancia de String que los llama.El compilador usará example como el argumento que se envía al primer parámetro.
Si un método de extensión se llama para un objeto que está establecido en Nothing, el método de extensión se ejecuta.Esto no se aplica a los métodos normales de la instancia.Puede comprobar explícitamente si hay Nothing en el método de extensión.
Tipos que se pueden extender
Puede definir un método de extensión en la mayoría de los tipos que se pueden representar en una lista de parámetros de Visual Basic, incluidos los siguientes:
Clases (tipos de referencia)
Estructuras (tipos de valor)
Interfaces
Delegados
Argumentos ByRef y ByVal
Parámetros de método genérico
Matrices
Puesto que el primer parámetro especifica el tipo de datos que el método de extensión extiende, es obligatorio y no puede ser opcional.Por esa razón, los parámetros Optional y ParamArray no pueden ser el primer parámetro de la lista de parámetros.
Los métodos de extensión no se consideran en los enlaces en tiempo de ejecución.En el siguiente ejemplo, la instrucción anObject.PrintMe() genera una excepción MissingMemberException, la misma excepción que se produciría si se eliminara la segunda definición del método de extensión PrintMe.
VB
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
Procedimientos recomendados
Los métodos de extensión proporcionan una manera conveniente y eficaz de extender un tipo existente.Sin embargo, para usarlos correctamente se deben tener en cuenta algunos puntos.Estas consideraciones se aplican principalmente a los autores de bibliotecas de clases, pero podrían afectar a cualquier aplicación que use métodos de extensión.
Más en general, los métodos de extensión que agrega a los tipos de los que no es propietario son más vulnerables que los métodos de extensión agregados a los tipos que controla.Se pueden producir algunos conflictos en las clases de las que no es propietario que pueden interferir con sus métodos de extensión.
Si existe cualquier miembro de instancia accesible con una firma compatible con los argumentos en la instrucción de llamada, sin requerir conversiones de restricción del argumento al parámetro, el método de instancia se usará antes que cualquier método de extensión.Por consiguiente, si se agrega un método de instancia adecuado a una clase en un momento dado, puede que un miembro de extensión existente en el que confía se vuelva inaccesible.
El autor de un método de extensión no puede evitar que otros programadores escriban métodos de extensión conflictivos que pueden tener prioridad sobre la extensión original.
Puede mejorar la solidez colocando los métodos de extensión en su propio espacio de nombres.Entonces, los usuarios de su biblioteca pueden incluir un espacio de nombres o excluirlo, o bien seleccionar entre los espacios de nombres, por separado en el resto de la biblioteca.
Puede ser más seguro extender interfaces que extender clases, sobre todo si no posee la interfaz o la clase.Un cambio en una interfaz afecta a cada clase que la implementa.Por consiguiente, es menos probable que el autor pueda agregar o cambiar métodos en una interfaz.Sin embargo, si una clase implementa dos interfaces que tienen métodos de extensión con la misma firma, ninguno de los métodos de extensión está visible.
Extienda el tipo más específico que pueda.En una jerarquía de tipos, si selecciona un tipo del que se derivan muchos otros tipos, hay niveles de posibilidades para la inclusión de métodos de instancia u otros métodos de extensión que podrían interferir con el suyo.
Métodos de extensión, métodos de instancia y propiedades
Cuando un método de instancia dentro del ámbito tiene una firma que es compatible con los argumentos de una instrucción de llamada, se elige el método de instancia de preferencia a cualquier método de extensión.El método de instancia tiene la prioridad aun cuando el método de extensión tenga una mejor coincidencia.En el ejemplo siguiente, ExampleClass contiene un método de instancia denominado ExampleMethod que tiene un parámetro de tipo Integer.El método de extensión ExampleMethod extiende ExampleClass y tiene un parámetro de tipo Long.
VB
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
La primera llamada a ExampleMethod en el código siguiente llama al método de extensión, porque arg1 es Long y sólo es compatible con el parámetro Long en el método de extensión.La segunda llamada a ExampleMethod tiene un argumento Integer, arg2, y llama al método de instancia.
VB
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
Ahora invierta los tipos de datos de los parámetros en los dos métodos:
VB
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
Ahora el código de Main llama al método de instancia las dos veces.Esto se debe a que arg1 y arg2 tienen una conversión de ampliación a Long, y el método de instancia tiene prioridad sobre el método de extensión en ambos casos.
VB
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
Por lo tanto, un método de extensión no puede reemplazar a un método de instancia existente.Sin embargo, cuando un método de extensión tiene el mismo nombre que un método de instancia pero las firmas no entran en conflicto, se puede tener acceso a ambos métodos.Por ejemplo, si la clase ExampleClass contiene un método denominado ExampleMethod que no toma ningún argumento, se permiten métodos de extensión con el mismo nombre pero con firmas diferentes, como se muestra en el código siguiente.
VB
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
Los resultados de este código son los siguientes:
Extension method
Instance method
La situación es más fácil con propiedades: si un método de extensión tiene el mismo nombre que una propiedad de la clase que extiende, el método de extensión no está visible y no se puede tener acceso a él.
Prioridad del método de extensión
Cuando dos métodos de extensión con firmas idénticas están en el ámbito y se encuentran accesibles, se invoca al de mayor prioridad.La prioridad de un método de extensión se basa en el mecanismo que se usa para incluir al método en el ámbito.La lista siguiente muestra la jerarquía de prioridad, de mayor a menor.
Métodos de extensión definidos dentro del módulo actual.
Métodos de extensión definidos dentro de los tipos de datos en el espacio de nombres actual o cualquiera de sus elementos primarios. Los espacios de nombres secundarios tienen mayor prioridad que los espacios de nombres primarios.
Métodos de extensión definidos dentro de cualquier tipo de importaciones en el archivo actual.
Métodos de extensión definidos dentro de cualquier importación de espacio de nombres en el archivo actual.
Métodos de extensión definidos dentro de cualquier tipo de importaciones de nivel de proyecto.

Métodos de extensión definidos dentro de cualquier importación de espacio de nombres de nivel de proyecto.

EVENTO


Eventos

A pesar de que se puede visualizar un proyecto de Visual Studio como una serie de procedimientos que se ejecutan consecutivamente, en realidad la mayoría de los programas están dirigidos por eventos, es decir, el flujo de ejecución está determinado por elementos externos denominados eventos.
Un evento es una señal que comunica a una aplicación que ha sucedido algo importante. Por ejemplo, cuando un usuario hace clic en un control de un formulario, el formulario puede provocar un evento Click y llamar a un procedimiento que controla el evento. Los eventos también permiten que las tareas separadas se comuniquen. Suponga, por ejemplo, que una aplicación realiza una tarea de ordenación independientemente de la aplicación principal. Si un usuario cancela la ordenación, la aplicación puede enviar un evento de cancelación que ordene la detención del proceso de ordenación.
Esta sección describe los términos y conceptos que se utilizan con eventos en Visual Basic.
Los eventos se declaran en clases, estructuras, módulos e interfaces mediante la palabra clave Event, como se muestra en el siguiente ejemplo:
VB
Event AnEvent(ByVal EventNumber As Integer)
Un evento es como un mensaje que anuncia que ha pasado algo importante. A la acción de difundir el mensaje se le llama producir el evento. En Visual Basic, los eventos se generan con la instrucción RaiseEvent, como en el ejemplo siguiente:
VB
RaiseEvent AnEvent(EventNumber)
Los eventos se deben provocar dentro del ámbito de la clase, módulo o estructura donde se declaran. Por ejemplo, una clase derivada no puede producir eventos heredados de una clase base.
Cualquier objeto capaz de producir un evento es un remitente de eventos, y también recibe el nombre de origen de eventos. Los formularios, controles y objetos definidos por el usuario son ejemplos de remitentes de eventos.
Los controladores de eventos son procedimientos llamados cuando se produce un evento correspondiente. Puede utilizar cualquier subrutina válida con una firma coincidente como controlador de eventos. No obstante, no puede utilizar una función como controlador de eventos, porque no puede devolver un valor al origen del evento.
Visual Basic utiliza una convención de nomenclatura estándar para controladores de eventos que combina el nombre del remitente del evento, un signo de subrayado y el nombre del evento. Por ejemplo, el evento Click de un botón denominado button1 recibiría el nombre de Sub button1_Click.
Descripción: System_CAPS_noteNota
Es recomendable utilizar esta convención de nomenclatura al definir controladores de eventos para sus propios eventos, pero no es estrictamente necesario; puede utilizar cualquier nombre de subrutina válido.
Para que un controlador de eventos se pueda utilizar, primero debe asociarse a un evento mediante la instrucción Handles o AddHandler.
La instrucción WithEvents y la cláusula Handles proporcionan una forma declarativa de especificar controladores de eventos. Los eventos provocados por un objeto declarado con la palabra clave WithEvents pueden controlarse mediante cualquier procedimiento con una instrucción Handles para ese evento, tal y como se muestra en el ejemplo siguiente:
VB
' Declare a WithEvents variable.
Dim WithEvents EClass As New EventClass

' Call the method that raises the object's events.
Sub TestEvents()
    EClass.RaiseEvents()
End Sub

' Declare an event handler that handles multiple events.
Sub EClass_EventHandler() Handles EClass.XEvent, EClass.YEvent
    MsgBox("Received Event.")
End Sub

Class EventClass
    Public Event XEvent()
    Public Event YEvent()
    ' RaiseEvents raises both events.
    Sub RaiseEvents()
        RaiseEvent XEvent()
        RaiseEvent YEvent()
    End Sub
End Class
La instrucción WithEvents y la cláusula Handles son a menudo la mejor opción para los controladores de eventos, ya que la sintaxis declarativa que utilizan hace que el control de eventos sea más sencillo de codificar, leer y depurar. No obstante, tenga en cuenta las siguientes limitaciones en la utilización de las variables WithEvents:
  • No se puede utilizar una variable WithEvents como variable de objeto. Es decir, no es posible declararla como Object; se debe especificar el nombre de clase al declarar la variable.
  • Dado que los eventos compartidosno están asociados a instancias de clase, no se puede usar WithEvents para controlar eventos compartidos mediante declaración. De forma parecida, no se puede utilizar WithEvents ni Handles para controlar los eventos desde una estructura Structure. En ambos casos, puede utilizar la instrucción AddHandler para controlar esos eventos.
  • No se pueden crear matrices de variables WithEvents.
Las variables WithEvents permiten que un solo controlador controle uno o más tipos de eventos, así como que uno o más controladores de eventos controlen el mismo tipo de evento.
Aunque la cláusula Handles es la forma estándar de asociar un evento a un controlador de eventos, está limitada a asociar eventos a controladores de eventos en tiempo de compilación.
En algunos casos, como con eventos asociados a formularios o controles, Visual Basic desactiva automáticamente un controlador de eventos vacío y lo asocia a un evento. Por ejemplo, al hacer doble clic en un botón de comando en un formulario en modo de diseño, Visual Basic crea un controlador de eventos vacío y una variable WithEvents para el botón de comando, como en el código siguiente:
VB
Friend WithEvents Button1 As System.Windows.Forms.Button
Protected Sub Button1_Click() Handles Button1.Click
End Sub
La instrucción AddHandler se parece a la cláusula Handles en que las dos permiten especificar un controlador de eventos. Sin embargo,AddHandler, utilizado con RemoveHandler, proporciona más flexibilidad que la cláusula Handles, lo que permite agregar, quitar y cambiar de forma dinámica el controlador de errores asociado con un evento. Si desea controlar eventos compartidos o eventos de una estructura, debe utilizar AddHandler.
AddHandler toma dos argumentos: el nombre de un evento de un remitente de evento, como un control, y una expresión que evalúa a un delegado. No necesita especificar explícitamente la clase delegada al utilizar AddHandler, ya que la instrucción AddressOf siempre devuelve una referencia al delegado. El ejemplo siguiente asocia un controlador de eventos a un evento provocado por un objeto:
VB
AddHandler Obj.XEvent, AddressOf Me.XEventHandler
RemoveHandler, que desconecta un evento de un controlador de eventos, utiliza la misma sintaxis que AddHandler. Por ejemplo:
VB
RemoveHandler Obj.XEvent, AddressOf Me.XEventHandler
En el ejemplo siguiente, un controlador de eventos se asocia a un evento y se genera el evento. El controlador de eventos detecta el evento y muestra un mensaje.
A continuación, se quita el primer controlador de eventos y se asocia al evento un controlador de eventos diferente. Cuando el evento se vuelve a generar, se muestra un mensaje diferente.
Finalmente, se quita el segundo controlador de eventos y el evento se genera por tercera vez. Dado que ya no hay ningún controlador de eventos asociado al evento, no se realiza ninguna acción.
VB
Module Module1

    Sub Main()
        Dim c1 As New Class1
        ' Associate an event handler with an event.
        AddHandler c1.AnEvent, AddressOf EventHandler1
        ' Call a method to raise the event.
        c1.CauseTheEvent()
        ' Stop handling the event.
        RemoveHandler c1.AnEvent, AddressOf EventHandler1
        ' Now associate a different event handler with the event.
        AddHandler c1.AnEvent, AddressOf EventHandler2
        ' Call a method to raise the event.
        c1.CauseTheEvent()
        ' Stop handling the event.
        RemoveHandler c1.AnEvent, AddressOf EventHandler2
        ' This event will not be handled.
        c1.CauseTheEvent()
    End Sub

    Sub EventHandler1()
        ' Handle the event.
        MsgBox("EventHandler1 caught event.")
    End Sub

    Sub EventHandler2()
        ' Handle the event.
        MsgBox("EventHandler2 caught event.")
    End Sub

    Public Class Class1
        ' Declare an event.
        Public Event AnEvent()
        Sub CauseTheEvent()
            ' Raise an event.
            RaiseEvent AnEvent()
        End Sub
    End Class

End Module
Las clases derivadas (clases que heredan características de una clase base) pueden controlar eventos provocados por su clase base mediante la instrucción HandlesMyBase.
Controlar eventos de una clase base
  • Declare un controlador de eventos en la clase derivada agregando una instrucción Handles MyBase.nombreDeEvento a la línea de declaración del procedimiento controlador de eventos, donde nombreDeEvento es el nombre del evento de la clase base que está controlando. Por ejemplo:
VB
Public Class BaseClass
    Public Event BaseEvent(ByVal i As Integer)
    ' Place methods and properties here.
End Class

Public Class DerivedClass
    Inherits BaseClass
    Sub EventHandler(ByVal x As Integer) Handles MyBase.BaseEvent
        ' Place code to handle events from BaseClass here.
    End Sub
End Class