Microsoft.com Home | Site Map
MSDN
Search Microsoft.com for:
| Developer Centers | Library | Downloads | How to Buy | Subscribers | Worldwide
Search for


Advanced Search
MSDN Magazine Archive CD
http://www.odc2008.com
MSDN Magazine  

 
 
Elija su idioma:  
Instintos básicos
Expresiones lambda



Contenido


L
as nuevas expresiones lambda de Visual Basic® 2008, son una adición útil en el cuadro de herramientas de cualquier programador. Son entidades que se pueden llamar, definidas dentro de una función y ciudadanos de primera clase; se puede devolver una expresión lambda desde una función y pasar expresiones lambda a otras funciones. Las expresiones lambda se agregaron a Visual Basic 2008, cuyo nombre en código original era "Orcas", para compatibilidad con LINQ (Language Integrated Query), que agrega programabilidad de datos a Visual Basic (trataremos de esto más adelante). Cuando use las expresiones lambda, comenzará a comprobar la eficacia y flexibilidad que promueven. Le invito a probar los conceptos básicos de las expresiones lambda, a explorar sus ventajas y a ser testigo de cómo usarlas para escribir programas más expresivos.


¿Qué son las expresiones lambda?

A continuación se muestra un ejemplo de una definición básica de expresión lambda. Se define doubleIt como una expresión lambda que toma un entero y devuelve un entero. La expresión lambda toma de forma eficaz la entrada, la multiplica por 2 y posteriormente devuelve el resultado.

Dim doubleIt As Func(Of Integer, Integer) = _
    Function(x As Integer) x * 2

El tipo Func también es nuevo en Visual Basic 2008; esencialmente es un delegado en el que el tipo devuelto se especifica como el último parámetro genérico y permite suministrar hasta cuatro argumentos como parámetros genéricos anteriores (existen en realidad varios delegados Func, y cada uno de ellos acepta un número específico de parámetros). El tipo delegado Func se define en el ensamblado System.Core.dll del espacio de nombres System. Todos los nuevos proyectos creados con Visual Basic tendrán automáticamente una referencia a System.Core.dll, de modo que puede aprovechar de inmediato el tipo Func.

El siguiente código muestra las distintas sobrecargas de Func:

Dim f0 As Func(Of Boolean)
Dim f1 As Func(Of Integer, Boolean)
Dim f4 As Func(Of Integer, Integer, Integer, Integer, Boolean)

Aquí, f0 es un delegado que devuelve un booleano, f1 es un delegado que toma un entero y devuelve un booleano y f4 es un delegado que toma cuatro argumentos enteros y devuelve un booleano. El punto clave a tener en cuenta es que una expresión lambda se escribe igual que un delegado; es decir, es una entidad que se puede llamar, igual como los delegados en Visual Basic 2005.

A la derecha de la asignación en el primer fragmento de código, puede ver la nueva sintaxis de expresión lambda. Comienza con la palabra clave Function, que posteriormente va seguida por una lista de argumentos y una expresión única.

En el ejemplo anterior, la expresión lambda toma un argumento, x, que es un entero. Sin embargo, observe que no existe una instrucción de retorno. Eso es porque el compilador de Visual Basic ya conoce el tipo según la expresión y por eso resulta superflua una instrucción de retorno. En este caso, como x es un entero, 2 * x también lo es, así que el resultado de la expresión lambda es un entero.

La magia de una expresión lambda es que simplemente la puede invocar como un delegado normal, como puede ver aquí:

Dim doubleIt As Func(Of Integer, Integer) = _
    Function(x As Integer) x * 2
Dim z = doubleIt(20)

Si ejecuta este código, verá que el valor almacenado en z es 40. Esencialmente, ha creado una expresión lambda que duplica cualquier valor entero que le suministre.

Consideremos un ejemplo más complejo —un generador de expresiones lambda:

Dim mult As Func(Of Integer, Func(Of Integer, Integer)) = _
    Function(x As Integer) Function(y As Integer) x * y

Mult es una expresión lambda bastante compleja; toma como entrada un argumento entero y devuelve otra expresión lambda que toma como entrada un argumento entero y devuelve un entero. La sintaxis es un poco complicada, pero las siguientes continuaciones y formato de línea pueden ayudar a indicar la estructura anidada exacta:

Dim mult As Func(Of Integer, Func(Of Integer, Integer)) = _
    Function(x As Integer) _
        Function(y As Integer) x * y

De este modo debería ser un poco más claro; la expresión lambda exterior contiene otra expresión lambda, que el compilador usa como instrucción de retorno. La firma de la expresión lambda interior coincide con la firma de delegado de Func (Of Integer, Integer) en el argumento return de la expresión lambda exterior, así que el compilador compila la instrucción correctamente.

¿Cómo usaría una expresión lambda así?

Dim mult_10 = mult(10)
Dim r = mult_10(4)

En este caso, la primera línea define que mult_10 es mult(10). Debido a que Mult(10) devuelve una lambda que toma un argumento y lo multiplica por 10, el tipo de mult_10 es Func(Of Integer, Integer). La segunda línea llama a mult_10 con el valor 4, así que el resultado de r es 40 y el tipo de r es Integer.

Esencialmente, mult es un generador de expresiones lambda. Devuelve expresiones lambda personalizadas por el primer argumento. Es posible que haya advertido que la expresión lambda interior hace referencia al parámetro de la expresión lambda exterior, pero la vigencia de la expresión lambda interior supera a la de la exterior. Trataré más adelante sobre este levantamiento de variable.

Back to top

Expresiones lambda como devoluciones de llamada

Debido a que las expresiones lambda son simplemente delegados, puede usarlas en cualquier parte en que use delegados. Considere el método siguiente, que toma un delegado y llama al delegado de cada elemento en una lista:

Delegate Function ShouldProcess(Of T)(element As T) As Boolean

Sub ProcessList(Of T)( _
        elements As List(Of T), shouldProcess As ShouldProcess(Of T))
    For Each elem in elements
        If shouldProcess(elem) Then
            ' Do some processing here
        End If
    Next
End Sub

Esta es una aplicación de delegados bastante estándar; el método ProcessList recorre cada uno de los elementos de la lista, comprueba si debe procesar el elemento, y posteriormente realiza algún procesamiento estándar.

Para usarla en Visual Basic 2005, tendría que definir una función en su clase o módulo que tenga la misma firma que el delegado, y posteriormente pasar la dirección de la función al procedimiento ProcessList, de este modo (observe el código en rojo):

Class Person
    Public age As Integer
End Class

Function _PrivateShouldProcess(person As Person) As Boolean
    Return person.age > 50
End Function

Sub DoIt()
    Dim list As New List(Of Person)
    ' Obtain list of Person from a database, for example
    ProcessList(list, AddressOf _PrivateShouldProcess)
End Sub

En el mejor de los casos, esto es molesto; a menudo tiene que indagar a través de la documentación del código para determinar qué firma impone el delegado, y posteriormente tiene que hacer que coincida exactamente. Además, si necesita llamar a ProcessList con muchas funciones shouldProcess diferentes, contamina su código con una cantidad de pequeñas funciones privadas.

Veamos cómo puede llamar a esta función con expresiones lambda:

Class Person
    Public age As Integer
End Class

Sub DoIt()
    Dim list As New List(Of Person)
    ' Obtain list of Person from a database, for example
    ProcessList(list, Function(person As Person) person.age > 50)
End Sub    

Me encanta la elegancia y sencillez de las expresiones lambda. No hay necesidad de crear su propia función para realizar el procesamiento lógico. El delegado se define en el punto en que se usa, que es mucho mejor que definirlo en un método privado en alguna parte y que pierda proximidad con el que usa el método privado.

Estoy seguro que puede comprobar de qué manera las expresiones lambda son eficaces, útiles, y pueden hacer su código más fácil de leer y mantenerse. Las características más avanzadas como la inferencia de tipos agregan aún más eficacia.

Una limitación a tener en cuenta es que una expresión lambda es justamente eso: una expresión única. En Visual Basic 2008, sólo puede tener una expresión única en una expresión lambda. Más adelante en este artículo, le mostraré un nuevo operador ternario presentado en Visual Basic 2008 que le permitirá construir expresiones condicionales, pero la característica actual no admitirá declaraciones arbitrarias en una expresión lambda.

Pero antes de explorar los conceptos más profundos que hay tras las expresiones lambda, analizaré en primer lugar por qué se presentaron las expresiones lambda.

Back to top

¿Por qué agregar expresiones lambda?

Para admitir consultas LINQ, fue necesario agregar algunas características; entre ellas estaban las expresiones de Visual Basic y lambda. Supongamos que tiene la siguiente instrucción de consulta en Visual Basic:

Dim q = From p In Process.GetProcesses() _
        Where p.PriorityClass = ProcessPriorityClass.High _
        Select p

Se dedica mucho trabajo de forma subyacente para lograr compilar esta instrucción de consulta. A alto nivel, el compilador itera en la colección Process.GetProcesses, aplica el filtro Where a la misma, y devuelve una lista de procesos que coinciden con el filtro en la cláusula Where.

Observe que hay una expresión de Visual Basic dentro de la cláusula Where: p.PriorityClass = ProcessPriorityClass.High. Para ejecutar este filtro, el compilador crea una expresión lambda para el filtro Where y la aplica a cada elemento de la lista de procesos:

Dim q = Process.GetProcesses().Where( _
            Function(p) p.PriorityClass = ProcessPriorityClass.High)

Esencialmente, la expresión lambda ofrece un atajo para que el compilador emita métodos y los asigne a delegados; se encarga de todo esto automáticamente. La ventaja que obtiene con una expresión lambda y que no le ofrece una combinación de delegado/función es que el compilador realiza la inferencia de tipos de forma automática en los argumentos lambda. En el ejemplo anterior, el tipo de argumento p se infiere mediante el uso; en este caso, el argumento Where define el tipo de expresión lambda, y el tipo para el argumento de la expresión lambda es inferido por el compilador. Las características de inferencia de tipos admitidas por el compilador son una adición eficaz a Visual Basic. Veamos cómo pueden ayudarle.

Back to top

Inferencia de tipos

La introducción de mecanismos eficaces de inferencia de tipos significa que no debe preocuparse en resolver el tipo de cada variable. Además, la inferencia de tipos habilita escenarios que de otro modo serían imposibles. Miremos tres diferentes maneras en que se infieren tipos cuando se usan expresiones lambda.

Inferir tipos de argumentos de expresiones lambda  Este escenario es realmente útil si tiene un tipo delegado al que desea asignar una lambda y no desea especificar los argumentos completamente:

Dim lambda As Func(Of Integer, Integer) = Function(x) x * x

En el ejemplo, la variable lambda se escribe como Func(Of Integer, Integer). Esto es un delegado que toma un argumento entero y devuelve un argumento entero. Como resultado, el compilador infiere automáticamente que el argumento x de la lambda es entero, y que el valor de retorno de lambda es entero.

También se puede aprovechar de la inferencia de tipos de argumentos de expresiones lambda cuando llame a un método que tome un delegado. Considere una modificación de un ejemplo anterior:

Delegate Function ShouldProcess(Of T)(element As T) As Boolean

Sub ProcessList(Of T)( _
        elements As List(Of T), shouldProcess As ShouldProcess(Of T))
    ' Method body removed for brevity
End Sub

En este caso, la función ProcessList toma una expresión lambda.

Puede llamar al procedimiento de este modo:

Sub DoIt()
    Dim list As New List(Of A)
    ' fill or obtain elements in list
    ProcessList(list, Function(a) a.x > 50)
End Sub

Observe que no especifiqué el tipo del argumento de lambda como hice anteriormente, aunque el compilador infiere que es Person. ¿Cómo puede sucede algo así? Bueno, en realidad hay varios niveles de inferencia de tipos en este ejemplo.

Primero, el compilador ve que ProcessList es un procedimiento genérico que toma como entrada List(Of T) y ShouldProcess(Of T). En la llamada a ProcessList, el compilador ve el primer argumento es una lista y que esa lista es una List(Of Person). Debido a que el segundo argumento no ofrece pistas sobre el tipo de T, el compilador decide que T es de tipo Person. A continuación, infiere que el argumento genérico para ShouldProcess (Of T) es Person y por eso infiere que el segundo argumento es ShouldProcess(Of Person). Finalmente, debido a que la expresión lambda no suministró un tipo para su argumento, el compilador conoce el tipo de argumento basándose en la firma de delegado de ShouldProcess(Of Person) e infiere que el tipo del parámetro (a) es Person. Este es un modelo muy eficaz para la inferencia de tipos; no es necesario conocer el tipo de los argumentos delegados al construir la lambda y, de hecho, recomiendo que permita que el compilador se encargue del trabajo más difícil. Afortunadamente, dispone de Intellisense® y de informaciones sobre herramientas que ayudan a indicar cuál es el tipo inferido, lo que le permite ser igual de productivo, o aún más.

Inferir el tipo de resultado  Este escenario es realmente útil si no tiene un tipo delegado y desea que el compilador lo sintetice automáticamente. Es una característica disponible sólo en Visual Basic:

Dim lambda = Function(x As Integer) x * x

En el ejemplo, el tipo de la expresión lambda está completamente especificado (el argumento x de la lambda es de tipo entero y el compilador infiere que el valor devuelto es un entero, dado que entero * entero = entero). Sin embargo, la variable de lambda no tiene tipo. Por lo tanto, el compilador sintetizará un delegado anónimo que coincida con la forma de la expresión lambda y asignará ese tipo delegado a la lambda.

Esta es una gran característica porque significa que puede crear expresiones lambda sobre la marcha sin tener que construir estáticamente sus tipos delegados. Por ejemplo, ¿cuántas veces estuvo en una situación en que necesita aplicar una condición a un conjunto de variables y necesita hacerlo en varios lugares como en la figura 1? Hubo muy pocas veces en que he estado programando y me encontré con una situación como ésta. Normalmente la crearía externamente para poder hacer la comprobación de la condición en un solo lugar y no hacerlo de forma dispersa en toda la función.

Pero hay veces en que la comprobación se usa sólo en esta función y en ninguna otra parte; no quiero contaminar mi clase con funciones de aplicación auxiliar aleatorias, que sólo se usan para la compatibilidad de esta función. Si lo hiciera de este modo, afectaría negativamente la capacidad de mantenimiento, ¿qué sucede si otra persona llama a esta función y necesita realizar un cambio? También podría contaminar los nombres; las clases con muchos métodos privados me parecen realmente difíciles de seguir. Y podría hacer que Intellisense sea menos útil porque cada vez existen más entradas en la lista de Intellisense. Además, se afecta la proximidad de la lógica. Si hago un método privado separado, me gustaría que se encuentre físicamente cercano al método que lo usa. Cuando muchas personas trabajan en la misma base de código, a largo plazo puede ser difícil mantener esta proximidad. Usar expresiones lambda y hacer que el compilador cree automáticamente las clases delegadas soluciona estos problemas, como se muestra en la figura 2.

He creado la lógica externamente para comprobar algunas condiciones en la clase Motorcycle, no en un método privado donde existen desventajas, sino en una expresión lambda donde el compilador creará automáticamente un tipo delegado (que está oculto) y enlazará todo el trabajo necesario para que pueda llamar a la expresión lambda como si fuera un método.

Me encanta este enfoque porque pone la lógica cerca de la implementación (dentro del cuerpo del método), se incluye (sólo una copia), y el compilador se encarga de gran parte del mantenimiento. Funciona bien porque puede crear una expresión arbitrariamente compleja como cuerpo para la expresión lambda.

Enlace en tiempo de ejecución: inferir objetos  En este escenario, no se escriben ni la variable lambda ni la expresión lambda:

Dim lambda = Function(x) x * x

Aquí, el compilador también genera automáticamente un delegado anónimo, pero los tipos de la lambda son System.Object. Esto significa que en este escenario el enlace en tiempo de ejecución está habilitado cuando Option Strict se establece en off.

Este es un escenario realmente sencillo para quienes usan enlace en tiempo de ejecución. Las expresiones lambda son completamente compatibles con operaciones enlazadas en tiempo de ejecución, así que en el ejemplo anterior, mientras el operador * esté definido en los tipos que le ofrece a la lambda, funcionará:

Dim a = lambda(10)
Dim b = lambda(CDec(10))
Dim c = lambda("This will throw an exception because " & _
               "strings don't support the * operator")

Como puede ver en los ejemplos anteriores, mientras el tipo de tiempo de ejecución tenga un operador * , todo funcionará bien. Las expresiones lambda de esta naturaleza se adaptan muy bien al modelo de enlace en tiempo de ejecución en Visual Basic.

Back to top

Generación de código de forma subyacente

Ahora que he explorado las expresiones lambda, veamos la clase de código que genera el compilador. Considere el ejemplo anterior:

Sub TestLambda()
    Dim doubleIt As Func(Of Integer, Integer) = _
        Function(x As Integer) x * 2
    Console.WriteLine(doubleIt(10))
End Sub

Como ya sabe, Func es un delegado y los delegados son sólo punteros a las funciones, así que: ¿cómo hace el compilador para que esta magia funcione? En este caso, el compilador emite automáticamente una nueva función y establece el delegado para que apunte a la nueva función:

Function $GeneratedFunction$(x As Integer) As Integer
    Return x * 2
End Sub

Sub TestLambda()
    Dim doubleIt As Func(Of Integer, Integer) = _
        AddressOf $GeneratedFunction$
    Console.WriteLine(doubleIt(10))
End Sub

El compilador esencialmente toma la expresión lambda y crea una nueva función con su contenido, y cambia la instrucción de asignación de modo tal que la expresión lambda tomará la dirección de la función generada. En este caso la función se genera en el mismo elemento principal que contiene el método que usa la expresión lambda. Si TestLambda se define en una clase C, entonces la función generada se definirá en C. Tenga en cuenta que la función generada no se puede llamar y se marca como privada.

Back to top

Expresiones lambda y levantamiento de variable

En los ejemplos anteriores, los cuerpos de las expresiones lambda se referían a variables pasadas en la lambda. Sin embargo, la eficacia de las expresiones lambda se podrá ver con el levantamiento de variable. Como sugerí anteriormente, el compilador "realiza algo de magia" en ciertas situaciones. No obstante, antes de explorar estos escenarios, aprendamos algunos conceptos básicos de la rama de las matemáticas denominada cálculo lambda, las expresiones lambda se basan en un concepto similar.

El concepto fundamental en el cálculo lambda es que una función puede tener variables libres o variables enlazadas. Las variables libres son aquellas que se definen en las variables del método contenedor (locales y parámetros). Las variables enlazadas son aquellas que se definen en la firma lambda o son miembros de la clase que contiene la lambda, incluidas las clases base.

Es muy importante realizar la distinción entre variables enlazadas y libres en sus expresiones lambda porque afectan la semántica de la expresión lambda, el código que se genera, y en última instancia, la exactitud del programa. Este es un ejemplo de una expresión lambda que contiene variables enlazadas y libres:

Dim y As Integer = 10
Dim addTen As Func(Of Integer, Integer) = Function(ByVal x) x + y

Aquí, x se considera una variable enlazada dentro la lambda porque es un parámetro formal a la expresión lambda, e y se considera una variable libre porque es una variable que pertenece al método contenedor de la expresión lambda.

Recuerde que después de definir una expresión lambda, se trata como un tipo delegado (puede devolver la expresión lambda desde un método, por ejemplo). Considere lo siguiente:

Function MakeLambda() As Func(Of Integer, Integer)
    Dim y As Integer = 10
    Dim addTen As Func(Of Integer, Integer) = Function(ByVal x) x + y
    Return addTen
End Function

Sub UseLambda()
    Dim addTen = MakeLambda()
    Console.WriteLine(addTen(5))
End Sub

Este código imprimirá "15" en la consola cuando se llame a UseLambda. Pero, quizás se pregunte: ¿cómo funciona? La función MakeLambda define y como variable local, y la lambda usa y, pero regresa fuera de la función MakeLambda. La función UseLambda obtiene la lambda de MakeLambda y ejecuta la lambda, y de algún modo parece que la variable y se "recuerda" en la lambda.

¿Se trata de algún tipo de truco en segundo plano? La vigencia de y es el método de MakeLambda. Cuándo ejecutamos la lambda que regresa de MakeLambda, MakeLambda ha salido del ámbito y su espacio de pila se ha eliminado. Pero y se definió en la pila y, de algún modo, quedó "pegada" a la lambda.

Esta adherencia es la magia que comúnmente se conoce como levantamiento de variable. En este caso, a la variable y se la conoce como variable levantada. Y, como puede ver, las variables levantadas son eficaces: El compilador se encarga de mucho trabajo para capturar el estado de las variables y los conserva fuera de sus vigencias normales.

Más formalmente, cuando el compilador encuentra una expresión lambda que tiene variables libres, las levantará en una clase denominada cierre. La vigencia del cierre se extiende más allá de la vigencia de las variables libres levantadas en la misma. El compilador reescribe el acceso a la variable en el método para tener acceso a la variable que se encuentra dentro de la instancia de cierre.

Primero, examinemos otra vez el ejemplo de MakeLambda:

Function MakeLambda() As Func(Of Integer, Integer)
    Dim y As Integer = 10
    Dim addTen As Func(Of Integer, Integer) = Function(ByVal x) x + y
    Return Lambda
End Function

Como analizamos antes, x se enlaza al parámetro de la lambda pero y es una variable libre. El compilador lo detecta y avanza para crear una clase del cierre que captura las variables libres, así como la definición de la expresión lambda:

Public Class _Closure$__1
    Public y As Integer
    Public Function _Lambda$__1(ByVal x As Integer) As Integer
        Return x + Me.y
    End Function
End Class

Puede ver que la variable del cierre captura la variable y, y la almacena en la clase del cierre. La variable libre se convierte entonces en una variable enlazada en la clase del cierre.

El compilador también reescribe el método que contiene la expresión lambda, y el aspecto será similar al siguiente:

Function MakeLambda() As Func(Of Integer, Integer)
    Dim Closure As New _Closure$__1
    Closure.y = 10
    Return AddressOf Closure._Lambda$__1
End Function

Ahora puede ver cómo el compilador crea la variable del cierre, reescribe la variable local y que se levanta en la variable del cierre, inicializa la variable, y devuelve simplemente la dirección de la expresión lambda que se escribe en la clase del cierre.

Es importante tener en cuenta que el compilador sólo levanta variables libres en la expresión lambda. El estado de la variable se captura en el cierre, que existe mientras la expresión lambda exista.

Veamos otro ejemplo:

Sub Test()
    Dim y As Integer = 10
    Dim Lambda As Func(Of Integer, Integer) = Function(ByVal x) x + y
    y = 20
    Console.WriteLine(Lambda(5))
End Sub

¿Qué valor se muestra cuando ejecuta esta función? Si dijo 25, acertó. ¿Por qué 25? Bien, el compilador captura y reescribe todas las variables libres y en la copia del cierre, de la siguiente manera:

Sub Test()
    Dim Closure As New $CLOSURE_Compiler_Generated_Name$
    Closure.y = 10
    Dim Lambda = AddressOf Closure.Lambda_1
    Closure.y = 20
    Console.WriteLine(Lambda(5))
End Function

Como puede ver, en el momento que la expresión lambda se ejecuta, el valor de y ha cambiado a 20 y de este modo, cuando la expresión lambda se ejecuta, devuelve 5 + 20.

Esto es realmente importante cuando en lo referente a bucles. Debido a que las variables libres se capturan en un único cierre, podría obtener comportamientos inesperados, si por ejemplo, genera un subproceso que usa la expresión lambda con una variable capturada que cambia:

Sub Test()
    For I = 1 To 5
        StartThread(Function() I + 10)
    Next
End Function

En este ejemplo, suponga que StartThread crea un nuevo subproceso e imprime el resultado de la expresión lambda a la consola. Debido a que I está capturado en el cierre, es posible que cuando el subproceso ejecute la expresión lambda, el bucle for haya modificado el valor de I. En ese caso, el programa podría no imprimir 11, 12, 13, 14, y 15 como se esperaba. En vez de eso, tiene que evaluar la variable capturada dentro del bucle for:

Sub Test()
    For I = 1 To 5
        Dim x = I
        StartThread(Function() x + 10)
    Next
End Function

Ahora este código capturará el valor de x en el cierre y el programa imprimirá 11, 12, 13, 14, y 15 como se esperaba. Es muy importante conocer qué variables se levantan, cuándo se ejecutarán las expresiones lambda y cuándo pueden cambiar las variables levantadas, para que pueda estar seguro de que su programa se ejecuta correctamente en todas las circunstancias.

Back to top

Aprovechar al máximo las expresiones lambda

En Visual Basic 2008, sólo puede suministrar una expresión como cuerpo de la lambda, pero también se introduce una nueva palabra clave ternary que permite realizar expresiones condicionales, sencillas y de tipo completamente especificado:

Dim x = If(condition, 10, 20)

La palabra clave If es similar a la llamada a función IIF, excepto que la palabra clave If tiene seguridad de tipos completa. En el ejemplo anterior, esto significa que el compilador deduce que ambas ramas de la palabra clave If devuelven un entero y así aplica reglas de inferencia de tipos y decide que el tipo de x es Integer. Cuando se usa IIF, x será de tipo object.

Puede usar la palabra clave If en una expresión lambda:

Dim x = Function(c As Customer) _
    If(c.Age >= 18, c.Address, c.Parent.Address)

En este ejemplo, se asume que existe una clase Customer cuya definición incluye una propiedad Address que representa, como esperaría, la dirección actual del cliente. La expresión lambda usa la expresión ternary para aplicar una condición en el argumento de entrada; si el cliente tiene 18 años o más, devuelve su dirección. De lo contrario, devuelve la dirección del padre.

Ahora se activa la inferencia de tipos y el compilador determina que el tipo devuelto de la expresión lambda es Address. A continuación, crea un tipo delegado para x (como se trató anteriormente), donde el tipo delegado toma como entrada Customer y devuelve Address.

Si está interesado en aprender más sobre expresiones lambda, se puede suscribir a mi blog (blogs.msdn.com/timng) donde analizaré las expresiones lambda (y otras características del lenguaje Visual Basic 2008) de forma más detallada.

Back to top

Envíe sus preguntas y comentarios a instinct@microsoft.com.

Timothy Ng es un ingeniero de desarrollo de software en el equipo Visual Basic Compiler de Microsoft. Ha trabajado en diversas características para el próximo lanzamiento de Visual Studio 2008, entre las que se cuentan la inferencia de tipos, los ensamblados de confianza, los árboles de expresión y los tipos anónimos. Puede ponerse en contacto con Tim en timng@microsoft.com.

Subscribe  Extraído del September 2007 número de MSDN Magazine.
Back to topBack to top QJ: 070909

© 2007 Microsoft Corporation and CMP Media, LLC. Reservados todos los derechos; queda prohibida la reproducción parcial o total sin previa autorización.

    © 2008 Microsoft Corporation. All rights reserved. Terms of Use |Trademarks |Privacy Statement
    Microsoft