62 votes

Rendre NameValueCollection accessible à la requête LINQ

Comment rendre NameValueCollection accessible à l'opérateur de requête LINQ tel que where, join, groupby ?

J'ai essayé ce qui suit :

private NameValueCollection RequestFields()
{
    NameValueCollection nvc = new NameValueCollection()
                                  {
                                      {"emailOption: blah Blah", "true"},
                                      {"emailOption: blah Blah2", "false"},
                                      {"nothing", "false"},
                                      {"nothinger", "true"}
                                  };
    return nvc;

}

public void GetSelectedEmail()
{
    NameValueCollection nvc = RequestFields();
    IQueryable queryable = nvc.AsQueryable();
}

Mais j'ai obtenu une ArgumentException me disant que la source n'est pas IEnumerable<>.

90voto

Bryan Watts Points 22810

Vous devez "transformer" le non-générique IEnumerable en un IEnumerable. Il a été suggéré d'utiliser OfType mais c'est une méthode de filtrage. Ce que vous faites équivaut à une conversion, pour laquelle il y a l'opérateur Cast :

var champs = RequestFields().Cast();

Comme Frans l'a souligné, cela ne donne accès qu'aux clés. Vous auriez encore besoin d'indexer dans la collection pour obtenir les valeurs. Voici une méthode d'extension pour extraire des KeyValuePair de NameValueCollection :

public static IEnumerable> ToPairs(this NameValueCollection collection)
{
    if(collection == null)
    {
        throw new ArgumentNullException("collection");
    }

    return collection.Cast().Select(clé => new KeyValuePair(clé, collection[clé]));
}

Éditer : En réponse à la demande de @Ruben Bartelink, voici comment accéder à l'ensemble complet de valeurs pour chaque clé en utilisant ToLookup :

public static ILookup ToLookup(this NameValueCollection collection)
{
    if(collection == null)
    {
        throw new ArgumentNullException("collection");
    }

    var paires =
        from clé in collection.Cast()
        from valeur in collection.GetValues(clé)
        select new { clé, valeur };

    return paires.ToLookup(paire => paire.clé, paire => paire.valeur);
}

Alternativement, en utilisant des tuples C# 7.0 :

public static IEnumerable<(String name, String value)> ToTuples(this NameValueCollection collection)
{
    if(collection == null)
    {
        throw new ArgumentNullException("collection");
    }

    return
        from clé in collection.Cast()
        from valeur in collection.GetValues(clé)
        select (clé, valeur);
}

11voto

David B Points 53123

AsQueryable doit prendre un IEnumerable, un générique. NameValueCollection implémente IEnumerable, ce qui est différent.

Plutôt que ceci:

{
    NameValueCollection nvc = RequestFields();
    IQueryable queryable = nvc.AsQueryable();
}

Essayez OfType (il accepte l'interface non générique)

{
    NameValueCollection nvc = RequestFields();
    IEnumerable canBeQueried = nvc.OfType();
    IEnumerable query =
       canBeQueried.Where(s => s.StartsWith("abc"));
}

8voto

Orion Adrian Points 8855

Un dictionnaire est probablement en réalité plus proche de ce que vous voulez utiliser car il remplira en fait plus des rôles que remplit NameValueCollection. Voici une variation de la solution de Bryan Watts :

public static class CollectionExtensions
{
    public static IDictionary ToDictionary(this NameValueCollection source)
    {
        return source.Cast().Select(s => new { Key = s, Value = source[s] }).ToDictionary(p => p.Key, p => p.Value); 
    }
}

7voto

NinjaNye Points 3734

Je sais que je suis en retard à la fête mais je voulais juste ajouter ma réponse qui ne comprend pas la méthode d'extension .Cast mais qui utilise plutôt la propriété AllKeys :

var fields = RequestFields().AllKeys;

Cela permettrait la méthode d'extension suivante :

public static IEnumerable> ToPairs(this NameValueCollection collection)
{
    if(collection == null)
    {
        throw new ArgumentNullException("collection");
    }

    return collection.AllKeys.Select(key => new KeyValuePair(key, collection[key]));
}

J'espère que cela aidera les futurs visiteurs

4voto

Frans Bouma Points 6015

Le problème est que la collection implémente IEnumerable (par opposition à IEnumerable) et énumérer la collection renvoie les clés, pas les paires.

Si j'étais vous, j'utiliserais un Dictionaryqui est énumérable et peut être utilisé avec LINQ.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X