NameValueCollection'da Anahtarın Var olup olmadığını kontrol edin


141

Bir anahtarın NameValueCollection öğesinde döngü yapmadan var olup olmadığını kontrol etmenin hızlı ve basit bir yolu var mı?

Dictionary.ContainsKey () veya benzeri bir şey mi arıyorsunuz?

Bunu çözmenin elbette birçok yolu var. Sadece birinin beyin kaşıntımı çizmeye yardım edip edemeyeceğini merak ediyorum.


Eğer: Sadece anahtarına dayalı bir arama yapmak istiyorsanız BTW .... Sözlüğü kullanmak olabilir bu sınıfın üzerinde dizinleyici kullanmak ama bu kendini döngü yapacak - hiçbir kazanç böylece
Carsten

Yanıtlar:


181

Gönderen MSDN :

Bu özellik aşağıdaki durumlarda null değerini döndürür:

1) belirtilen anahtar bulunmazsa;

Böylece şunları yapabilirsiniz:

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

2) belirtilen anahtar bulunursa ve ilişkili değeri null olursa.

collection[key]çağrıları base.Get()sonra base.FindEntry()dahili kullanan Hashtableperformans O (1) ile yıkanmıştır.


38
Bu özellik aşağıdaki durumlarda null değerini döndürür: 1) belirtilen anahtar bulunamazsa; ve 2) belirtilen anahtar bulunursa ve ilişkili değeri null olursa. Bu özellik iki durum arasında ayrım yapmaz.
Steve

1
@Andreas bu yüzden null yerine boş string saklamak daha iyidir
abatishchev

@Steve OP böyle bir çarpışma hakkında hiçbir şey söylemiyor.
abatishchev

13
Doğru @abatishchev, ancak OP 'bir anahtar olup olmadığını kontrol ediyor' diyor. Anahtar olmadığı için null değeri almak doğru değildir. Sonunda taviz vermeden cevap yok (döngü yok, boş dizeler kullan)
Steve

@abatishchev demek 0eşittir null... sry
Andreas Niedermair

54

Bu yöntemi kullanın:

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

    return true;
}

En verimli olanıdır NameValueCollectionve toplama nulldeğer içerip içermediğine bağlı değildir.


5
using System.Linq;Bu çözümü kullanırken unutmayın .
jhauberg

14

Bu cevapların hiçbirinin oldukça doğru / optimal olduğunu düşünmüyorum. NameValueCollection yalnızca null değerler ile eksik değerler arasında ayrım yapmakla kalmaz, aynı zamanda anahtarları açısından büyük / küçük harfe duyarsızdır. Böylece, tam bir çözüm olacağını düşünüyorum:

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

Bu çözümü seviyorum. NameValueCollectionBase kaynağına bakıldığında, varsayılan olarak InvariantCultureIgnoreCase kullanılır. Ancak bu, NameValueCollection öğesinin bir örneğini oluşturduğu herhangi bir sınıf yerine kullanmak için farklı bir tanesinin geçmediği anlamına gelmez.
lethek

12

Evet, AllKeysmülkü kontrol etmek için Linq'i kullanabilirsiniz :

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

Bununla birlikte Dictionary<string, string[]>, belki de bir uzatma yöntemi ile oluşturulan bu amaç için çok daha uygun olacaktır:

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
Bu, O (n) olan tüm koleksiyon üzerinde döngü yapacaktır. İken collection[key]dahili olarak kullandığı HashtableO (1)
abatishchev

4
@abatishchev Ancak collection[key]anahtarın bulunmaması ile bu anahtarın karşısındaki null değeri saklamak arasında hiçbir fark yoktur.
Rich O'Kelly

Ayrıca, kirli bir kesmek önceden şekillendirebilir ve Yansıma kullanarak Hashtable'ın özel alanını alabilirsiniz.
abatishchev

Bence bu oldukça aptalca bir çözüm. Birisi NameValueCollection kullanıyorsa, büyük olasılıkla null anahtarına sahip olmak gibi sözlüğün desteklenmemesinin nedenleri olabilir.
Chris Marisic

0

GetYöntemi kullanabilir ve NameValueCollection belirtilen anahtarı içermiyorsa nullyöntem döneceği için nulldenetleyebilirsiniz.

Bkz. MSDN .


Bilmen indexait keyyöntemini çağırmak için. Değil mi?
abatishchev

0

Koleksiyon boyutu küçükse, rich.okelly tarafından sağlanan çözümle gidebilirsiniz. Bununla birlikte, büyük bir koleksiyon, sözlüğün oluşturulmasının, sadece anahtarlar koleksiyonunu aramaktan belirgin şekilde daha yavaş olabileceği anlamına gelir.

Ayrıca, kullanım senaryonuz zaman içinde farklı noktalardaki anahtarları ararsa, NameValueCollection değiştirilmiş olabilir, her seferinde sözlüğü oluşturmak yine anahtar koleksiyonunu aramaktan daha yavaş olabilir.


0

Bu, yeni bir yöntem sunmak zorunda kalmadan da bir çözüm olabilir:

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

0

Referans kaynaklarında görebileceğiniz gibi, NameValueCollection NameObjectCollectionBase öğesinden devralır .

Böylece taban türünü alırsınız, özel hashtable'ı yansıma yoluyla alırsınız ve belirli bir anahtar içerip içermediğini kontrol edersiniz.

Mono'da da çalışması için, hashtable adının mono olarak ne olduğunu görmeniz gerekir, bu da burada görebileceğiniz bir şeydir (m_ItemsContainer) ve başlangıç ​​FieldInfo boşsa (mono- Çalışma süresi).

Bunun gibi

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

ultra saf yansıtıcı olmayan .NET 2.0 kodu için, hash tablosunu kullanmak yerine anahtarlar arasında geçiş yapabilirsiniz, ancak bu yavaştır.

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

VB'de:

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

C # 'da sadece şöyle olmalıdır:

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

Değil emin olması gerektiği takdirde nullya ""ama bu yardımcı olmalıdır.


Üzgünüm, VB. C # olmalıdır (MyNameValueCollection (Key)! = Null) {} Boş veya "" olup olmadığından emin değilim, ancak bu yardımcı olacaktır.
CodeShouldBeEasy

Doğru sözdiziminin, bir yöntem çağrısını beklemek yerine Dictionary, bir veri yapısına benzer olduğuna inanıyorum . MyNameValueCollection[Key]MyNameValueCollection(Key)
Blairg23

0

Bu koleksiyonu küçük elemanlar koleksiyonunda çalışırken kullanıyorum.

Öğeleri çok nerede, bence "Sözlük" kullanmak gerekir. Kodum:

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

Veya bunu kullanın:

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

0
queryItems.AllKeys.Contains(key)

Anahtarın benzersiz olmayabileceğini ve karşılaştırmanın genellikle büyük / küçük harfe duyarlı olduğunu unutmayın. Sadece ilk eşleşen anahtarın değerini almak ve durum hakkında rahatsız etmemek istiyorsanız bunu kullanın:

        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
   }

Dönüş Değeri Tür: NameValueCollection boş olmayan anahtarlar içeriyorsa System.Boolean true; aksi takdirde yanlış. LİNK


2
Bu soruya cevap verebilirken, özellikle bunun diğer birçok cevaba nasıl iyi bir alternatif olabileceğini açıklamak için bazı açıklamalar sıklıkla takdir edilmektedir.
Pac0

Bu, yalnızca koleksiyonun herhangi bir anahtar içerip içermediğini kontrol eder. OP belirli bir anahtarın varlığını istedi .
Bill Tür
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.