foreach KeyValuePair en NameValueCollection?


79

Tengo este codigo:

NameValueCollection nv = HttpUtility.ParseQueryString(queryString);        
foreach (KeyValuePair<String,String> pr in nv) {
    //process KeyValuePair          
}

Esto se compila, pero cuando intento ejecutarlo obtengo un archivo InvalidCastException.

¿Por qué es esto? ¿Por qué no puedo usar KeyValuePairpara iterar sobre a NameValueCollection, y qué debo usar en su lugar?


Me gusta esto porque puedo iniciar un diccionario sin tener que crear una variable de diccionario de respaldo además de un foreach. var nv = HttpUtility.ParseQueryString(Request.Url.Query); var qsDic = nv.Cast<object>().ToDictionary<object, string, object>(key => (string) key, key => nv[(string) key]);
— The Muffin Man

Respuestas:


133

En primer lugar, NameValueCollectionno usa KeyValuePair<String,String>. Además, foreachsolo expone la clave:

NameValueCollection nv = HttpUtility.ParseQueryString(queryString);        
foreach (string key in nv) {
    var value = nv[key];

}

3
Hmm, eso es un poco extraño. Hubiera esperado que hubiera una manera de obtener ambos a la vez.
— Oliver

27
Todos lo hacemos cuando empezamos a usar un NVC.
— jgauffin

1
Me preguntaba cómo hacer esto ... ¡gracias! Por cierto, no es necesario especificarlo, KeyValuePair<String,String>ya que NameValueCollection solo usa cadena, cadena. No es necesario especificarlo.
— TheGateKeeper

7
Tenga en cuenta cómo funciona este código para claves duplicadas. Cuando existen claves duplicadas, devolverá "clave valor1, valor2, valor3", en lugar de "clave valor1" luego "clave valor2" luego "clave valor3".
— Doug S

3
@Nick: NameValueCollection es uno de los primeros tipos de colección en .NET. Es sensible a mayúsculas y los valores de combinación existente (que es útil para algunos protocolos)
— jgauffin

12

No puede hacer eso directamente, pero puede crear un método de extensión como este:

public static IEnumerable<KeyValuePair<string, string>> AsKVP(
        this NameValueCollection source
)
{
    return source.AllKeys.SelectMany(
        source.GetValues,
        (k, v) => new KeyValuePair<string, string>(k, v));
}

Entonces puedes hacer:

NameValueCollection nv = HttpUtility.ParseQueryString(queryString);
foreach (KeyValuePair<String,String> pr in nv.AsKVP()) {
    //process KeyValuePair          
}

Nota: inspirado en esto . Se requiere SelectMany para manejar claves duplicadas.

Versión de vb.net:

<Extension>
Public Function AsKVP(
        source As Specialized.NameValueCollection
) As IEnumerable(Of KeyValuePair(Of String, String))
    Dim result = source.AllKeys.SelectMany(
        AddressOf source.GetValues,
        Function(k, v) New KeyValuePair(Of String, String)(k, v))
    Return result
End Function

10

Para referencia futura, también puede usar esta sintaxis:

foreach(string key in Request.QueryString)
{
    var value = Request.QueryString[key];
}

2
Bien. Si tiene acceso a la HttpRequestpuede omitir AllKeysya que la QueryStringpropiedad es una NameValueCollection.
— jgauffin

-1 porque no tienes que usar AllKeyscomo mencionó @jgauffin
— Warlock

@Warlock: Dar un -1 por eso es un poco duro. Puedes editar la respuesta, ¿no?
— jgauffin

Sí, lo siento, no quería lastimar a nadie :) Pero el problema no estaba solo en la propiedad. Si miras la respuesta de @jgauffin, propuso la misma idea, pero se publicó antes. Entonces, esta publicación parece una duplicación.
— Warlock

Si miras el último comentario, está escrito por mí jgauffiny las respuestas no están duplicadas si miras más de cerca.
— jgauffin

6

Otro método de extensión, con fines de aprendizaje:

    public static IEnumerable<KeyValuePair<string, string>> ToIEnumerable(this NameValueCollection nvc)
    {
        foreach (string key in nvc.AllKeys)
        {
            yield return new KeyValuePair<string, string>(key, nvc[key]);
        }
    }

¡Buena solución! Solo sugeriría usar en nvclugar de nvc.AllKeys. Me pregunto por qué los chicos de Microsoft no agregaron esto System.Linq. :)
— Warlock

2

NameValueCollection usa el enumerador de skool antiguo:

        var enu = ConfigurationManager.AppSettings.GetEnumerator();

        while(enu.MoveNext())
        {
            string key = (string)enu.Current;
            string value = ConfigurationManager.AppSettings[key];
        }

0

Me gustó esto y funciona:

 foreach (string akey in request.Query.Keys.Cast<string>())
     writer.WriteLine(akey + " = " + request.Query[akey]);

0

Tenga en cuenta que el nombre de la clave puede aparecer más de una vez en la cadena de consulta y que la comparación suele distinguir entre mayúsculas y minúsculas.
Si solo desea obtener el valor de la primera clave coincidente y no se preocupa por el caso, use esto:

        public string GetQueryValue(string queryKey)
        {
            foreach (string key in QueryItems)
            {
                if(queryKey.Equals(key, StringComparison.OrdinalIgnoreCase))
                    return QueryItems.GetValues(key).First(); // There might be multiple keys of the same name, but just return the first match
            }
            return null;
        }

-1
public static void PrintKeysAndValues2( NameValueCollection myCol )
{
    Console.WriteLine( "   [INDEX] KEY        VALUE" );
    for ( int i = 0; i < myCol.Count; i++ )
        Console.WriteLine( "   [{0}]     {1,-10} {2}", i, myCol.GetKey(i), myCol.Get(i) );
    Console.WriteLine();
}

http://msdn.microsoft.com/en-us/library/system.collections.specialized.namevaluecollection.aspx


-1 Muestra que es posible utilizar for para acceder a los NameValueCollectiondatos. Pero la pregunta es por qué no puede convertir NameValueCollectionelementos a KeyValuePair<string, string>. Quizás leíste la pregunta sin mucha atención. La mejor respuesta la dio jgauffin. Una interesante solución fue propuesta por Adrian Carneiro.
— Brujo
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.