ti-enxame.com

foreach KeyValuePair in NameValueCollection?

Eu tenho este código:

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

Isso compila, mas quando eu tento executá-lo eu recebo um InvalidCastException.

Por que é isso? Por que não posso usar KeyValuePair para iterar uma NameValueCollection e o que devo usar em vez disso?

71
Oliver

Primeiro de tudo, NameValueCollection não usa KeyValuePair<String,String>. Além disso, foreach expõe apenas a chave:

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

}
117
jgauffin

Para referência futura, você também pode usar esta sintaxe:

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

Você não pode fazer isso diretamente, mas pode criar um método de extensão da seguinte forma:

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

Então você pode fazer:

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

Nota: inspirado por this . SelectMany é necessário para lidar com chaves duplicadas.

vb.net version:

<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
9
Endy Tjahjono

Outro método de extensão, para fins de aprendizado:

    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]);
        }
    }
5
Adrian Carneiro

NameValueCollection usa o enumerador old-skool:

        var enu = ConfigurationManager.AppSettings.GetEnumerator();

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

Esteja ciente de que o nome da chave pode aparecer mais de uma vez na string de consulta e que a comparação geralmente faz distinção entre maiúsculas e minúsculas.
Se você quiser apenas obter o valor da primeira chave correspondente e não se incomodar com o caso, use isto:

        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;
        }
0
userSteve

Eu fiz assim e funciona:

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