2009-03-10 11 views
5

Estoy tratando de entender LINQ y tener confianza en su uso. Lo que estoy luchando son los parámetros solicitados. Ejemplo:Confundido acerca de los parámetros de LINQ

var sortedWords = words.OrderBy(a=>a.Length) 

words es una colección de matriz. intelisense OrderBy 's dice:

Func<string, TKey> keyselector 

Un func ejecuta un método y un string es el valor, TKey una clave. En el ejemplo http://msdn.microsoft.com/en-us/vcsharp/aa336756.aspx#thenBySimple (ThenBy - Comparer), comparamos la longitud diciendo a => a.Length. Entiendo esa sintaxis, pero ¿cómo se relaciona eso con lo que el intellisense está pidiendo?

Tiendo a encontrar el método signature e intellisense ilegible debido a todos los genéricos.

Gracias.

Respuesta

5
a => a.Length 

entiendo que la sintaxis, pero ¿cómo es el relacionado con lo que el intellisense está pidiendo?

Este fragmento de código es una expresión lambda.Una expresión lambda es una forma práctica de generar un método anónimo (en este caso) o un System.Linq.Expressions.Expression. Vamos a dividirlo por partes.

  • La característica más notable es la =>, que separa los parámetros a partir de un cuerpo de método.
  • En el lado izquierdo de =>, hay un símbolo: a. Esta es la declaración de un parámetro para nuestro método anónimo. El compilador sabe que estamos llamando a OrderBy(), y que OrderBy requiere un Func<string, object>. El parámetro para dicha función es una cadena, por lo que el compilador determina que a debe ser una cadena. Lo único que el programador debe proporcionar es un nombre.
  • En el lado derecho de =>, hay cuerpo de método. Como se trata de una línea, la palabra clave return está implícita. El IDE proporciona intellisense contra a como una cadena, que le permite usar la propiedad Length.

Ahora, considere esto C# 2.0 ...

IEnumerable<string> sortedWords = 
    Enumerable.OrderBy(words, delegate(string a) {return a.Length;}); 

Con la C# 3,0

IEnumerable<string> sortedWords = words 
    .OrderBy(a => a.Length); 
+0

Gracias por esto. ¡Tiene perfecto sentido ahora! :) – dotnetdev

+0

Además, si tuviera que obtener la cadena más corta primero, ¿hay alguna otra manera que decir a => a.Length y luego Invertir en la colección? – dotnetdev

+0

Si desea cambiar los pedidos, consulte OrderBy, OrderByDescending, ThenBy y ThenByDescending. –

0

Nunca me preocupo por el Intellisense, para ser sincero. Me estaba molestando temprano en mi Linqage. A medida que pasaba más tiempo con los genéricos y las expresiones, comenzó a tener sentido, pero hasta ese momento solo me interesaba la sintaxis.

Lo que quiere es una expresión lambda que le indique a Linq qué buscar para ordenar su colección.

Te siento, mi hermano, aguanta y tendrá sentido muy pronto.

6

El tipo (como muestra Intellisense) tiene sentido si comprende la naturaleza de lambda expressions en .NET/C#. De lo contrario, de hecho puede parecer un poco extraño para el recién llegado. Comience por considerar que el tipo de selector de clave, Func < TSource, TKey > es simplemente un delegado. Antes de C# 3.0, que se llama un procedimiento de este tipo por el que pasa un delegado como un parámetro, por ejemplo:

IEnumerable<string> sortedWords = words.OrderBy(new Func<string, int>(mySelectorMethod)); 

donde mySelectorMethod es el nombre de un método ordinario, que toma una cadenacomo parámetro y devuelve un int. (Como punto secundario, supongo que podría usar delegados anónimos, pero no vayamos allí por el momento). Además, tenga en cuenta que este ejemplo es puramente ilustrativo, ya que LINQ casi siempre se usa con .NET 3.5/C# 3.0 (aunque creo se puede usar con cualquiera/ambos .NET 2.0/C# 2.0 - alguien me corrige si estoy equivocado). Desde C# 3.0, los métodos se pueden definir en línea como expresiones lambda, que están destinadas a ser utilizadas precisamente en tales circunstancias. Lea el artículo de MSDN sobre expresiones lambda (vinculado arriba) si desea obtener una introducción adecuada, pero aquí simplemente describiré el uso en este contexto específico. Como usted indica, su código (en C 3.0 #) es algo así como lo siguiente:

var sortedWords = words.OrderBy(a => a.Length); 

La parte de la expresión que es a => a.Length es la expresión lambda, que es en realidad la abreviatura de declarar una función en línea. La sintaxis de las expresiones lambda es bastante simple en su mayor parte; a la izquierda de => se especifican los argumentos, generalmente en el formato (arg1, arg2, arg3), pero como solo hay uno en este caso, puede omitir los corchetes. A la derecha de => está la expresión que es el valor de retorno de la función (expresión lambda con mayor precisión).Alternativamente, puede adjuntar el código real con una declaración de devolución dentro de {y}, aunque esto generalmente no es necesario. Lo que creo que hace el compilador C# es reconocer el parámetro pasado a OrderBy como una expresión lambda y luego lo compila en una función y crea y pasa el delegado por usted. Tenga en cuenta que las expresiones lambda también se pueden convertir a System.Linq.Expressions.Expression objetos (árboles de expresiones accesibles) en lugar de delegados, pero este es un uso mucho menos común. De todos modos, aquí están pasando muchas cosas entre bastidores, pero espero que al menos esto aclare por qué el tipo es Func < TSource, TKey > y cómo se relaciona con la expresión lambda. Como dije, lea en MSDN si quiere una comprensión más profunda de LINQ/lambdas/delegados ...

1

Creo que el IntelliSense es realmente bastante útil, especialmente para los métodos genéricos que toman el tipo Func<..> como argumento, porque usted puede ver los tipos y tipos que lo guían para comprender lo que el método podría hacer.

Por ejemplo, los argumentos para OrderBy son IEnumerable<string> como un argumento 'this', lo que significa que tenemos alguna entrada que contiene un conjunto de cadenas. El primer argumento keySelector tiene un tipo Func<string, TKey>, lo que significa que es una expresión lambda que proporciona que especifica cómo obtener TKey desde string.

Esto ya sugiere que el método probablemente enumerará todos los elementos (cadenas) de la colección y puede usar el keySelector para obtener el valor de tipo TKey de cada elemento de la colección. El nombre TKey ya sugiere que usará este valor para comparar los elementos (cadenas) usando esta clave calculada. Sin embargo, si observa la otra sobrecarga que toma IComparer<TKey>, puede estar seguro de esto: este argumento especifica más detalles acerca de cómo desea comparar dos valores de tipo TKey, por lo que la función debe comparar los elementos utilizando esta clave .

... este tipo de pensamiento sobre los tipos toma algún tiempo para acostumbrarse, pero una vez que lo aprendas, puede ser extremadamente útil. Es más útil en el estilo de "funcional" de código, que a menudo se utiliza una gran cantidad de productos genéricos y expresiones Lamdba en C# 3.0 (y cosas similares en los lenguajes funcionales como F # u otros)

+0

Para hacer más clara a mí mismo. en realidad es la presentación y el espaciado de la frase intellisense en lugar de cualquier otra cosa lo que hace que sea un poco difícil para el ojo. :) – dotnetdev

+0

Sí, estoy de acuerdo, podría ser un poco más claro. Creo que es un poco difícil con la sintaxis de C#. Puede echar un vistazo a F #, que (creo) muestra información similar de manera muy concisa ... –

0

OrderBy() toma un delegado para una función que acepta un solo parámetro (en su caso, un string) y devuelve un valor del tipo que sustituye a TKey. Puede ser que el tipo de parámetro (cadena) ya se determinó desde llamó al método en una IEnumerable<string> pero el tipo de delegado sólo se resolverá como Func<string,int>después se infiere de la expresión lambda cuando está completamente especificado (es decir, a => a.Length). Si no le ha dado al analizador ninguna pista sobre lo que desea como clave de ordenación, solo mostrará TKey en IntelliSense hasta que pueda determinar el tipo deseado.

Cuestiones relacionadas