foreach KeyValuePair trong NameValueCollection?


79

Tôi có mã này:

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

Nó biên dịch, nhưng khi tôi cố gắng chạy nó, tôi nhận được InvalidCastException .

Tại sao thế này? Tại sao tôi không thể sử dụng KeyValuePairđể lặp qua a NameValueCollection, và tôi nên sử dụng gì để thay thế?


Tôi thích điều này vì tôi có thể nhập một từ điển mà không cần phải tạo một biến từ điển hỗ trợ ngoài một 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,

Câu trả lời:


129

Trước hết, NameValueCollectionkhông sử dụng KeyValuePair<String,String>. Ngoài ra, foreachchỉ để lộ khóa:

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

}

3
Hmm, thật kỳ lạ. Tôi đã mong đợi có một cách để có được cả hai cùng một lúc.
— Oliver

26
Tất cả chúng ta đều làm khi bắt đầu sử dụng NVC.
— jgauffin

1
Đã tự hỏi làm thế nào để làm điều này ... cảm ơn! Btw, bạn không cần chỉ định KeyValuePair<String,String>vì NameValueCollection chỉ sử dụng chuỗi, chuỗi. Không cần chỉ định nó.
— TheGateKeeper

7
Hãy biết mã này hoạt động như thế nào đối với các khóa trùng lặp. Khi các khóa trùng lặp tồn tại, nó sẽ trả về "key value1, value2, value3", thay vì "key value1" thì "key value2" rồi đến "key value3".
— Doug S

3
@Nick: NameValueCollection là một trong những kiểu tập hợp đầu tiên trong .NET. Đó là trường hợp nhạy cảm và giá trị hiện hợp nhất (đó là hữu ích đối với một số giao thức)
— jgauffin

11

Bạn không thể làm điều đó trực tiếp, nhưng bạn có thể tạo một phương thức mở rộng như sau:

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

Sau đó, bạn có thể làm:

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

Lưu ý: lấy cảm hứng từ điều này . SelectMany được yêu cầu để xử lý các khóa trùng lặp.

phiên bản 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

Để tham khảo trong tương lai, bạn cũng có thể sử dụng cú pháp này:

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

2
Tốt. Nếu bạn có quyền truy cập vào, HttpRequestbạn có thể bỏ qua AllKeysvì thuộc QueryStringtính là a NameValueCollection.
— jgauffin

-1 bởi vì bạn không cần phải sử dụng AllKeysnhư @jgauffin đề cập
— Warlock

@Warlock: Đưa ra -1 cho điều đó là hơi khắc nghiệt. Bạn có thể chỉnh sửa câu trả lời, phải không?
— jgauffin

Vâng, xin lỗi vì điều đó, tôi không muốn làm tổn thương bất kỳ ai :) Nhưng vấn đề không chỉ nằm ở tài sản. Nếu bạn nhìn vào câu trả lời của @ jgauffin, anh ấy đã đề xuất ý tưởng tương tự, nhưng nó đã được đăng trước đó. Vì vậy, bài đăng này trông giống như một bản sao.
— Warlock

Nếu bạn nhìn vào bình luận cuối cùng, nó được viết bởi tôi jgauffinvà các câu trả lời không trùng lặp nếu bạn nhìn kỹ hơn.
— jgauffin

6

Phương pháp mở rộng AN khác, dành cho mục đích học tập:

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

Giải pháp tốt! Tôi chỉ đề nghị sử dụng nvcthay vì nvc.AllKeys. Tôi tự hỏi tại sao những người của Microsoft không thêm điều này vào System.Linq. :)
— Warlock

2

NameValueCollection sử dụng trình điều tra old-skool:

        var enu = ConfigurationManager.AppSettings.GetEnumerator();

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

0

Tôi đã làm như thế này và nó hoạt động:

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

0

Lưu ý rằng tên khóa có thể xuất hiện nhiều lần trong chuỗi truy vấn và so sánh thường phân biệt chữ hoa chữ thường.
Nếu bạn chỉ muốn lấy giá trị của khóa phù hợp đầu tiên và không bận tâm về chữ hoa, hãy sử dụng cái này:

        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 Bạn cho thấy rằng có thể sử dụng for để truy cập NameValueCollectiondữ liệu. Nhưng câu hỏi là tại sao bạn không thể chuyển đổi NameValueCollectioncác mục sang KeyValuePair<string, string>. Có thể bạn đọc câu hỏi chưa kỹ lắm. Câu trả lời tốt nhất đã được đưa ra bởi jgauffin. Một giải pháp thú vị đã được đề xuất bởi Adrian Carneiro.
— Warlock
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.