LINQ: Comment déclarer IEnumerable[AnonymousType]?

C'est ma fonction:

    private IEnumerable<string> SeachItem(int[] ItemIds)
    {
        using (var reader = File.OpenText(Application.StartupPath + @"tempA_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;
        }
    }

j'obtiens une erreur de compilation, parce que "myLine" n'est pas une chaîne IEnumerable et je ne sais pas comment écrire IEnumerable[Anonymous]

"ne peut pas convertir implicitement le système de type'.Collection.Générique.IEnumerable [AnonymousType#1] Système "to".Collection.Générique.IEnumerable [string]'"

24
demandé sur Benjol 2009-05-23 20:28:00

5 réponses

Vous ne pouvez pas déclarer IEnumerable<AnonymousType> parce que le type n'a pas de nom (connu) au moment de la compilation. Donc, si vous voulez utiliser ce type dans une déclaration de fonction, d'en faire un type normal. Ou tout simplement modifier votre requête renvoie un IENumerable<String> et s'en tenir à ce type.

Ou retour IEnumerable<KeyValuePair<Int32, String>> en utilisant la déclaration select suivante.

select new KeyValuePair<Int32, String>(id, m.Groups[2].Value)
15
répondu Daniel Brückner 2009-05-23 16:36:39

la signature de La méthode sur SearchItem indique que la méthode renvoie un IEnumerable<string> mais le type anonyme déclaré dans votre requête LINQ n'est pas de type string. Si vous voulez garder la même signature de méthode, vous devez changer votre requête pour sélectionner seulement strings. par exemple,

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

si vous insistez pour retourner les données sélectionnées par votre requête, vous pouvez retourner un IEnumerable<object> si vous remplacez votre return déclaration

return myLine.Cast<object>();

alors vous pouvez consommer les objets en utilisant réflexion.

mais vraiment, si vous allez consommer un type anonyme en dehors de la méthode dans laquelle il est déclaré, Vous devriez définir une classe an avoir la méthode retourner un IEnumerable de la classe. Les types anonymes sont pratiques, mais ils peuvent faire l'objet d'abus.

9
répondu jason 2009-05-23 16:39:10

Je ne recommande pas nécessairement cela... C'est une sorte de subversion du système de type, mais vous pourriez faire ceci:

1) Changez votre signature de méthode pour retourner IEnumerable (non générique)

2) ajouter un cast par exemple helper:

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) alors appelez la méthode quelque chose comme ceci:

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);
}

et vous êtes finis.

la clé est le fait que si vous créez un type anonyme avec le même ordre, types et noms de propriétés à deux endroits les types seront réutilisés. Sachant cela, vous pouvez utiliser des génériques pour éviter la réflexion.

J'espère que cela aidera Alex

9
répondu Alex James 2009-05-23 17:06:13

votre fonction essaie de renvoyer IEnumerable, alors que le statement LINQ que vous exécutez renvoie en fait un IEnumerable où T est un type généré lors de la compilation. Les types anonymes ne sont pas toujours anonymes, car ils prennent un type spécifique et concret après que le code est compilé.

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 { ... }
}

cependant, si votre but ultime n'est pas de récupérer une sorte d'objet, et que vous êtes seulement intéressé par, disons, le chemin...alors vous pouvez encore générer un IEnumerable < string>:

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

j'espère que cela aidera à clarifier votre compréhension de LINQ, énumérables, et les types anonymes. :)

5
répondu jrista 2009-05-23 16:58:44

une chose à retenir est que LINQ consolidés exécution différée. Ce que cela signifie est que votre LINQ l'instruction n'est pas réellement exécutée jusqu'à ce que vous itériez sur elle dans un foreach déclaration ou vous appelez le .ToList() méthode myLine.

Pour votre exemple, essayez de changer:

return myLine;

À:

return myLine.ToList();
0
répondu Alexander Kahoun 2009-05-23 16:35:10