Kiểm tra xem Key có tồn tại trong NameValueCollection không


141

Có cách nào nhanh chóng và đơn giản để kiểm tra xem một khóa có tồn tại trong NameValueCollection mà không lặp qua nó không?

Tìm kiếm một cái gì đó như Dictionary.ContainsKey () hoặc tương tự.

Tất nhiên có nhiều cách để giải quyết điều này. Chỉ cần tự hỏi nếu ai đó có thể giúp gãi ngứa não của tôi.


chỉ sử dụng Từ điển nếu bạn muốn thực hiện tra cứu dựa trên khóa .... BTW: bạn có thể sử dụng trình chỉ mục trên lớp này nhưng điều này sẽ tự thực hiện vòng lặp - vì vậy không có lợi
Carsten

Câu trả lời:


181

Từ MSDN :

Khách sạn này trả về null trong các trường hợp sau:

1) nếu không tìm thấy khóa được chỉ định;

Vì vậy, bạn có thể chỉ:

NameValueCollection collection = ...
string value = collection[key];
if (value == null) // key doesn't exist

2) nếu tìm thấy khóa được chỉ định và giá trị liên quan của nó là null.

collection[key]các cuộc gọi base.Get()sau base.FindEntry()đó sử dụng nội bộ Hashtablevới hiệu suất O (1).


37
Thuộc tính này trả về null trong các trường hợp sau: 1) nếu không tìm thấy khóa được chỉ định; và 2) nếu tìm thấy khóa được chỉ định và giá trị liên quan của nó là null. Khách sạn này không phân biệt giữa hai trường hợp.
Steve

1
@Andreas đó là lý do tại sao tốt hơn để lưu trữ chuỗi trống thay vì null
abatishchev

@Steve OP không nói gì về vụ va chạm như vậy.
abatishchev

13
Đúng @abatishchev, tuy nhiên OP nói 'kiểm tra xem khóa có tồn tại không'. Lấy null làm khóa không tồn tại là không đúng. Cuối cùng, không có câu trả lời nào mà không có sự thỏa hiệp (không có vòng lặp, sử dụng các chuỗi trống)
Steve

@abatishchev Điều đó giống như nói 0bằng null... sry
Andreas Niedermair

54

Sử dụng phương pháp này:

private static bool ContainsKey(this NameValueCollection collection, string key)
{
    if (collection.Get(key) == null)
    {
        return collection.AllKeys.Contains(key);
    }

    return true;
}

Đó là cách hiệu quả nhất NameValueCollectionvà không phụ thuộc vào việc bộ sưu tập có chứa nullcác giá trị hay không.


5
Hãy nhớ using System.Linq;khi sử dụng giải pháp này.
jhauberg

14

Tôi không nghĩ bất kỳ câu trả lời nào là hoàn toàn đúng / tối ưu. NameValueCollection không chỉ không phân biệt giữa giá trị null và giá trị bị thiếu, nó còn không phân biệt chữ hoa chữ thường đối với các khóa của nó. Vì vậy, tôi nghĩ rằng một giải pháp đầy đủ sẽ là:

public static bool ContainsKey(this NameValueCollection @this, string key)
{
    return @this.Get(key) != null 
        // I'm using Keys instead of AllKeys because AllKeys, being a mutable array,
        // can get out-of-sync if mutated (it weirdly re-syncs when you modify the collection).
        // I'm also not 100% sure that OrdinalIgnoreCase is the right comparer to use here.
        // The MSDN docs only say that the "default" case-insensitive comparer is used
        // but it could be current culture or invariant culture
        || @this.Keys.Cast<string>().Contains(key, StringComparer.OrdinalIgnoreCase);
}

Tôi thích giải pháp này. Nhìn vào nguồn NameValueCollectionBase, nó mặc định sử dụng InvariantCARMIgnoreCase, tuy nhiên điều đó không có nghĩa là một cái khác không được truyền vào để sử dụng thay vào đó bởi bất kỳ lớp nào tạo ra một thể hiện của NameValueCollection.
lethek

12

Có, bạn có thể sử dụng Linq để kiểm tra AllKeystài sản:

using System.Linq;
...
collection.AllKeys.Contains(key);

Tuy nhiên, một Dictionary<string, string[]>mục đích phù hợp hơn với mục đích này, có lẽ được tạo ra thông qua một phương thức mở rộng:

public static void Dictionary<string, string[]> ToDictionary(this NameValueCollection collection) 
{
    return collection.Cast<string>().ToDictionary(key => key, key => collection.GetValues(key));
}

var dictionary = collection.ToDictionary();
if (dictionary.ContainsKey(key))
{
   ...
}

1
Điều đó sẽ lặp lại trên toàn bộ bộ sưu tập là O (n). Trong khi collection[key]sử dụng nội bộ Hashtablelà O (1)
abatishchev

4
@abatishchev Thật vậy, tuy nhiên, collection[key]không có sự phân biệt giữa khóa không có mặt và giá trị null được lưu trữ đối với khóa đó.
Rich O'Kelly

Ngoài ra, bạn có thể tạo ra một bản hack bẩn và truy xuất trường riêng của Hashtable bằng Reflection.
abatishchev

Tôi nghĩ rằng đây là một giải pháp khá ngớ ngẩn. Nếu ai đó đang sử dụng NameValueCollection, có thể vì lý do từ điển không được hỗ trợ, chẳng hạn như có khóa null.
Chris Marisic

0

Bạn có thể sử dụng Getphương thức và kiểm tra xem nullphương thức sẽ trả về nullnếu NameValueCollection không chứa khóa được chỉ định.

Xem MSDN .


Bạn cần phải biết indexcủa keyđể gọi phương thức. Không bạn
abatishchev

0

Nếu kích thước bộ sưu tập nhỏ, bạn có thể sử dụng giải pháp được cung cấp bởi rich.okelly. Tuy nhiên, một bộ sưu tập lớn có nghĩa là việc tạo từ điển có thể chậm hơn đáng kể so với việc chỉ tìm kiếm bộ sưu tập khóa.

Ngoài ra, nếu kịch bản sử dụng của bạn đang tìm kiếm các khóa ở các thời điểm khác nhau, trong đó NameValueCollection có thể đã được sửa đổi, việc tạo từ điển mỗi lần có thể, chậm hơn là chỉ tìm kiếm bộ sưu tập khóa.


0

Đây cũng có thể là một giải pháp mà không cần phải giới thiệu một phương pháp mới:

    item = collection["item"] != null ? collection["item"].ToString() : null;

0

Như bạn có thể thấy trong các nguồn tham chiếu, NameValueCollection kế thừa từ NameObjectCollectionBase .

Vì vậy, bạn lấy loại cơ sở, lấy hashtable riêng thông qua sự phản chiếu và kiểm tra xem nó có chứa một khóa cụ thể không.

Để nó hoạt động trong Mono, bạn cần xem tên của hashtable là gì trong mono, đây là thứ bạn có thể thấy ở đây (m_ItemsContainer) và lấy trường đơn sắc, nếu FieldInfo ban đầu là null (mono- thời gian chạy).

Như thế này

public static class ParameterExtensions
{

    private static System.Reflection.FieldInfo InitFieldInfo()
    {
        System.Type t = typeof(System.Collections.Specialized.NameObjectCollectionBase);
        System.Reflection.FieldInfo fi = t.GetField("_entriesTable", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

        if(fi == null) // Mono
            fi = t.GetField("m_ItemsContainer", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

        return fi;
    }

    private static System.Reflection.FieldInfo m_fi = InitFieldInfo();


    public static bool Contains(this System.Collections.Specialized.NameValueCollection nvc, string key)
    {
        //System.Collections.Specialized.NameValueCollection nvc = new System.Collections.Specialized.NameValueCollection();
        //nvc.Add("hello", "world");
        //nvc.Add("test", "case");

        // The Hashtable is case-INsensitive
        System.Collections.Hashtable ent = (System.Collections.Hashtable)m_fi.GetValue(nvc);
        return ent.ContainsKey(key);
    }
}

đối với mã .NET 2.0 không phản chiếu cực kỳ tinh khiết, bạn có thể lặp qua các phím, thay vì sử dụng bảng băm, nhưng điều đó rất chậm.

private static bool ContainsKey(System.Collections.Specialized.NameValueCollection nvc, string key)
{
    foreach (string str in nvc.AllKeys)
    {
        if (System.StringComparer.InvariantCultureIgnoreCase.Equals(str, key))
            return true;
    }

    return false;
}

0

Trong VB đó là:

if not MyNameValueCollection(Key) is Nothing then
.......
end if

Trong C # chỉ nên là:

if (MyNameValueCollection(Key) != null) { }

Không chắc chắn nếu nó nên nullhoặc ""nhưng điều này sẽ giúp.


Xin lỗi đó là trong VB. C # chỉ nên là if (MyNameValueCollection (Key)! = Null) {} Không chắc chắn nếu nó là null hoặc "" nhưng điều này sẽ giúp ích.
CodeShouldBe Easy

Tôi tin rằng cú pháp đúng tương tự như Dictionarycấu trúc dữ liệu, như trong MyNameValueCollection[Key], hơn là MyNameValueCollection(Key), mong đợi một cuộc gọi phương thức.
Blairg23

0

Tôi đang sử dụng bộ sưu tập này, khi tôi làm việc trong bộ sưu tập các yếu tố nhỏ.

Trường hợp nhiều yếu tố, tôi nghĩ cần sử dụng "Từ điển". Mã của tôi:

NameValueCollection ProdIdes;
string prodId = _cfg.ProdIdes[key];
if (string.IsNullOrEmpty(prodId))
{
    ......
}

Hoặc có thể được sử dụng này:

 string prodId = _cfg.ProdIdes[key] !=null ? "found" : "not found";

0
queryItems.AllKeys.Contains(key)

Xin lưu ý rằng khóa có thể không phải là duy nhất và việc so sánh thường phân biệt chữ hoa chữ thường. Nếu bạn muốn chỉ nhận giá trị của khóa khớp đầu tiên và không bận tâm về trường hợp thì hãy sử dụng điều 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
NameValueCollection n = Request.QueryString;

if (n.HasKeys())
   {
       //something
   }

Kiểu giá trị trả về: System.Boolean true nếu NameValueCollection chứa các khóa không null; mặt khác, sai LIÊN KẾT


2
Trong khi điều này có thể trả lời câu hỏi, một số giải thích thường được đánh giá cao, đặc biệt là để giải thích làm thế nào điều này có thể là một thay thế tốt cho nhiều câu trả lời khác.
Pac0

Điều này chỉ kiểm tra nếu bộ sưu tập có chứa bất kỳ khóa nào không. OP yêu cầu sự tồn tại của một khóa nhất định .
Bill Tür
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 cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.