2009-05-23 14 views
22

Esta es mi función:LINQ: ¿Cómo declarar IEnumerable [AnonymousType]?

private IEnumerable<string> SeachItem(int[] ItemIds) 
    { 
     using (var reader = File.OpenText(Application.StartupPath + @"\temp\A_A.tmp")) 
     { 
      var myLine = from line in ReadLines(reader) 
         where line.Length > 1 
         let id = int.Parse(line.Split('\t')[1]) 
         where ItemIds.Contains(id) 
         let m = Regex.Match(line, @"^\d+\t(\d+)\t.+?\t(item\\[^\t]+\.ddj)") 
         where m.Success == true 
         select new { Text = line, ItemId = id, Path = m.Groups[2].Value }; 
      return myLine; 
     } 
    } 

me sale un error de compilación, porque "myline" no es un [cadena] IEnumerable y no sé cómo escribir IEnumerable [Anónimo]

"no puede convertir implícitamente el tipo 'System.Collections.Generic.IEnumerable [AnonymousType # 1]' a 'System.Collections.Generic.IEnumerable [cadena]'"

Respuesta

15

No se puede declarar IEnumerable<AnonymousType> porque el tipo no tiene nombre (conocido) en tiempo de compilación. Por lo tanto, si desea utilizar este tipo en una declaración de función, hágalo de forma normal. O simplemente modifique su consulta para devolver un IENumerable<String> y quédese con ese tipo.

O regrese IEnumerable<KeyValuePair<Int32, String>> usando la siguiente instrucción de selección.

select new KeyValuePair<Int32, String>(id, m.Groups[2].Value) 
+2

Cuando dices "select new {...}", hiciste un AnonymousType. Si seleccionas una cadena, entonces debería funcionar. –

+0

No, pero puede devolver IEnumerable y usar el truco CastByExample. No recomendado. –

0

Una cosa para recordar es que LINQ declaraciones utilizan deferred execution. Lo que eso significa es que su instrucción LINQ en realidad no se ejecuta hasta que itere sobre ella en una declaración foreach o llame al método .ToList() en myLine.
Para su ejemplo pruebe a cambiar:

return myLine; 

Para:

return myLine.ToList(); 
+0

El problema está en la definición del procedimiento, por lo que debe ser "Lista privada SeachItem (int [] ItemIDs)", pero que no funciona bien. "No se puede convertir implícitamente el tipo Enumera [AnoynymousType # 1] en List [string]. Por favor dime si es simplemente imposible de hacer. :) –

8

La firma del método de SearchItem indica que el método devuelve un IEnumerable<string> pero el tipo anónimo declarado en su consulta LINQ no es del tipo string. Si desea mantener la misma firma de método, debe cambiar su consulta para seleccionar solo string s. p.ej.

return myLine.Select(a => a.Text); 

Si insiste en devolver los datos seleccionados por su consulta, puede devolver un IEnumerable<object> si cambia su estado de return con

return myLine.Cast<object>(); 

A continuación, puede consumir los objetos que utilizan la reflexión.

Pero realmente, si va a consumir un tipo anónimo fuera del método en el que está declarado, debe definir una clase y hacer que el método devuelva un IEnumerable de esa clase. Los tipos anónimos son convenientes pero están sujetos a abuso.

5

Su función está tratando de volver IEnumerable <cadena>, cuando la declaración de LINQ se está ejecutando es en realidad devuelve un IEnumerable <T> donde T es un tipo generado en tiempo de compilación. Los tipos anónimos no siempre son anónimos, ya que adquieren un tipo específico y concreto después de compilar el código.

Los tipos anónimos, sin embargo, dado que son efímeros hasta que se compilan, solo se pueden usar dentro del ámbito en el que se crean.Para apoyar sus necesidades en el ejemplo que nos ha facilitado, yo diría que la solución más sencilla es crear una entidad simple que almacena los resultados de la consulta:

public class SearchItemResult 
{ 
    public string Text { get; set; } 
    public int ItemId { get; set; } 
    public string Path { get; set; } 
} 

public IEnumerable<SearchItemResult> SearchItem(int[] itemIds) 
{ 
    // ... 
    IEnumerable<SearchItemResult> results = from ... select new SearchItemResult { ... } 
} 

Sin embargo, si su objetivo final no es para recuperar algún tipo de objeto, y sólo está interesado en, por ejemplo, el Camino ... entonces todavía se puede generar un IEnumerable <cadena>:

IEnumerable<string> lines = from ... select m.Groups[2].Value; 

espero que ayuda a aclarar su comprensión de LINQ, enumerables, y los tipos anónimos. :)

+1

FYI: No es estrictamente correcto decir que los tipos anónimos son exclusivos del ámbito en el que se crean. Tipos anónimos estructuralmente equivalente en el mismo a El ensamblado pero utilizado en dos métodos diferentes en realidad se comparte a través de esos métodos. Hay formas inteligentes de aprovechar este hecho, pero no los recomendaría; si necesita compartir un tipo en dos métodos, hágalo nominal. –

+0

¿Es ésa la fama de Eric Lippert de Microsoft? Ahora que has abierto la bolsa, debes dejar salir al gato. ¿Cómo comparte un tipo anónimo en todos los ámbitos? ;) – jrista

+1

Con mucho cuidado. Tienes que usar trucos de inferencia de tipo método goofy y variables externas capturadas. Tal vez haga un blog sobre eso en algún momento. –

6

No estoy necesariamente recomendar este ... Es una especie de subversión del sistema de tipos, pero se podía hacer esto:

1) cambiar su método de firma para volver IEnumerable (el que no genérica)

2) añadir un ayudante cast by example:

public static class Extensions{ 
    public static IEnumerable<T> CastByExample<T>(
      this IEnumerable sequence, 
      T example) where T: class 
    { 
     foreach (Object o in sequence) 
      yield return o as T; 
    } 
} 

3) a continuación, llamar al método algo como esto:

var example = new { Text = "", ItemId = 0, Path = "" }; 
foreach (var x in SeachItem(ids).CastByExample(example)) 
{ 
    // now you can access the properties of x 
    Console.WriteLine("{0},{1},{2}", x.Text, x.ItemId, x.Path); 
} 

Y listo.

La clave para esto es el hecho de que si crea un tipo anónimo con el mismo orden, tipos y nombres de propiedades en dos lugares, los tipos serán reutilizados. Sabiendo esto, puede usar medicamentos genéricos para evitar la reflexión.

Esperanza esto ayuda Alex

+0

Inteligente. Pero realmente, si alguien va a tener tantos problemas, deberían simplemente encapsular los datos en una clase declarada. – jason

+2

Como ya he dicho, no lo recomiendo;) –

+0

... curiosamente, solo tienes este problema una vez, es decir, una vez que tienes el método de extensión de ayuda esto es fácil de usar una y otra vez. A diferencia de enrollar nuevos tipos en todas partes. De todos modos, este es un trabajo para Tuple en .NET 4.0 –

Cuestiones relacionadas