Apa yang lebih efisien: Kamus TryGetValue atau ContainsKey + Item?

251

Dari entri MSDN di Dictionary.TryGetValue Method :

Metode ini menggabungkan fungsionalitas metode ContainsKey dan properti Item.

Jika kunci tidak ditemukan, maka parameter nilai mendapatkan nilai default yang sesuai untuk tipe nilai TValue; misalnya, 0 (nol) untuk tipe integer, false untuk tipe Boolean, dan null untuk tipe referensi.

Gunakan metode TryGetValue jika kode Anda sering mencoba mengakses kunci yang tidak ada dalam kamus. Menggunakan metode ini lebih efisien daripada menangkap KeyNotFoundException yang dilemparkan oleh properti Item.

Metode ini mendekati operasi O (1).

Dari deskripsi, tidak jelas apakah itu lebih efisien atau hanya lebih mudah daripada memanggil ContainsKey dan kemudian melakukan pencarian. Apakah implementasi TryGetValuehanya memanggil ContainsKey dan kemudian Item atau sebenarnya lebih efisien dari itu dengan melakukan pencarian tunggal?

Dengan kata lain, apa yang lebih efisien (yaitu mana yang melakukan pencarian lebih sedikit):

Dictionary<int,int> dict;
//...//
int ival;
if(dict.ContainsKey(ikey))
{
  ival = dict[ikey];
}
else
{
  ival = default(int);
}

atau

Dictionary<int,int> dict;
//...//
int ival;
dict.TryGetValue(ikey, out ival);

Catatan: Saya tidak mencari patokan!

Rado
sumber

Jawaban:

313

TryGetValue akan lebih cepat.

ContainsKeymenggunakan cek yang sama dengan TryGetValue, yang secara internal merujuk ke lokasi entri aktual. The Itemproperti sebenarnya memiliki fungsi kode hampir identik sebagai TryGetValue, kecuali bahwa ia akan melempar pengecualian bukannya kembali palsu.

Menggunakan ContainsKeydiikuti oleh Itemdasarnya duplikat fungsi pencarian, yang merupakan bagian terbesar dari perhitungan dalam kasus ini.

Reed Copsey
sumber
2
Ini lebih halus: if(dict.ContainsKey(ikey)) dict[ikey]++; else dict.Add(ikey, 0);. Tapi saya pikir itu TryGetValuemasih lebih efisien karena get dan set properti indexer digunakan, bukan?
Tim Schmelter
4
Anda benar-benar dapat melihat sumber .net untuk itu sekarang juga: referenceource.microsoft.com/#mscorlib/system/collections/… Anda dapat melihat bahwa ketiga TryGetValue, ContainsKey, dan ini [] memanggil metode FindEntry yang sama dan lakukan jumlah pekerjaan yang sama, hanya berbeda dalam cara mereka menjawab pertanyaan: trygetvalue mengembalikan bool dan nilainya, berisi kunci hanya mengembalikan benar / salah, dan ini [] mengembalikan nilai atau melempar pengecualian.
John Gardner
1
@ JohnGardner Ya, itulah yang saya katakan - tetapi jika Anda melakukan ContainsKey kemudian mendapatkan Item, Anda melakukan pekerjaan itu 2x bukannya 1x.
Reed Copsey
3
Saya setuju sepenuhnya :) Saya baru saja menunjukkan bahwa sumber yang sebenarnya tersedia sekarang. tidak ada jawaban lain / etc memiliki tautan ke sumber yang sebenarnya: D
John Gardner
1
Sedikit topik, jika Anda mengakses melalui IDictionary di lingkungan multithreaded saya akan selalu menggunakan TryGetValue karena negara dapat berubah dari saat Anda memanggil ContainsKey (tidak ada jaminan bahwa TryGetValue secara internal akan mengunci dengan benar, tetapi mungkin lebih aman)
Chris Berry
91

Patokan cepat menunjukkan bahwa TryGetValuememiliki sedikit keunggulan:

    static void Main() {
        var d = new Dictionary<string, string> {{"a", "b"}};
        var start = DateTime.Now;
        for (int i = 0; i != 10000000; i++) {
            string x;
            if (!d.TryGetValue("a", out x)) throw new ApplicationException("Oops");
            if (d.TryGetValue("b", out x)) throw new ApplicationException("Oops");
        }
        Console.WriteLine(DateTime.Now-start);
        start = DateTime.Now;
        for (int i = 0; i != 10000000; i++) {
            string x;
            if (d.ContainsKey("a")) {
                x = d["a"];
            } else {
                x = default(string);
            }
            if (d.ContainsKey("b")) {
                x = d["b"];
            } else {
                x = default(string);
            }
        }
   }

Ini menghasilkan

00:00:00.7600000
00:00:01.0610000

membuat ContainsKey + Itemakses sekitar 40% lebih lambat dengan asumsi paduan yang merata antara hit dan miss.

Terlebih lagi, ketika saya mengubah program untuk selalu ketinggalan (yaitu selalu melihat ke atas "b") kedua versi menjadi sama cepatnya:

00:00:00.2850000
00:00:00.2720000

Namun, ketika saya menjadikannya "semua hit", TryGetValuesisanya tetap menjadi pemenang yang jelas:

00:00:00.4930000
00:00:00.8110000
dasblinkenlight
sumber
11
Tentu saja, itu tergantung pada pola penggunaan yang sebenarnya. Jika Anda hampir tidak pernah gagal mencari maka TryGetValueharus jauh di depan. Juga ... nitpick ... DateTimebukan cara terbaik untuk menangkap pengukuran kinerja.
Ed S.
4
@EdS. Anda benar, TryGetValuesemakin jauh ke depan. Saya mengedit jawaban untuk memasukkan skenario "semua hit" dan "semua ketinggalan".
dasblinkenlight
2
@Luciano menjelaskan bagaimana Anda menggunakan Any- Seperti ini: Any(i=>i.Key==key). Dalam hal ini, ya, itu adalah pencarian linear kamus yang buruk.
weston
13
DateTime.Nowhanya akan akurat hingga beberapa ms. Gunakan Stopwatchkelas System.Diagnosticssebagai gantinya (yang menggunakan QueryPerformanceCounter di bawah selimut untuk memberikan akurasi yang jauh lebih tinggi). Lebih mudah digunakan juga.
Alastair Maw
5
Selain komentar Alastair dan Ed - DateTime. Sekarang bisa mundur, jika Anda mendapatkan pembaruan waktu, seperti yang terjadi ketika pengguna memperbarui waktu komputer mereka, zona waktu dilintasi, atau perubahan zona waktu (DST, untuk contoh). Cobalah bekerja pada sistem yang memiliki jam sistem disinkronkan ke waktu yang disediakan oleh beberapa layanan radio seperti GPS atau jaringan ponsel. DateTime.Now akan pergi ke semua tempat, dan DateTime.UtcNow hanya memperbaiki salah satu penyebabnya. Cukup gunakan StopWatch.
antiduh
51

Karena sejauh ini tidak ada jawaban yang benar-benar menjawab pertanyaan, berikut adalah jawaban yang dapat diterima yang saya temukan setelah beberapa penelitian:

Jika Anda mendekompilasi TryGetValue Anda melihat itu melakukan ini:

public bool TryGetValue(TKey key, out TValue value)
{
  int index = this.FindEntry(key);
  if (index >= 0)
  {
    value = this.entries[index].value;
    return true;
  }
  value = default(TValue);
  return false;
}

sedangkan metode ContainsKey adalah:

public bool ContainsKey(TKey key)
{
  return (this.FindEntry(key) >= 0);
}

jadi TryGetValue hanya ContainsKey plus pencarian array jika item ada.

Sumber

Tampaknya TryGetValue akan hampir dua kali lebih cepat dari kombinasi ContainsKey + Item.

Rado
sumber
20

Siapa peduli :-)

Anda mungkin bertanya karena sulit TryGetValuedigunakan - jadi enkapsulasi seperti ini dengan metode ekstensi.

public static class CollectionUtils
{
    // my original method
    // public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key)
    // {
    //    V ret;
    //    bool found = dic.TryGetValue(key, out ret);
    //    if (found)
    //    {
    //        return ret;
    //    }
    //    return default(V);
    // }


    // EDIT: one of many possible improved versions
    public static TValue GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key)
    {
        // initialized to default value (such as 0 or null depending upon type of TValue)
        TValue value;  

        // attempt to get the value of the key from the dictionary
        dictionary.TryGetValue(key, out value);
        return value;
    }

Lalu panggil saja:

dict.GetValueOrDefault("keyname")

atau

(dict.GetValueOrDefault("keyname") ?? fallbackValue) 
Simon_Weaver
sumber
1
@ Hüseyin Saya menjadi sangat bingung bagaimana saya cukup bodoh untuk memposting ini tanpa thistetapi ternyata saya memiliki metode saya digandakan dua kali di basis kode saya - sekali dengan dan satu tanpa thisjadi itu sebabnya saya tidak pernah menangkapnya! terima kasih sudah memperbaiki!
Simon_Weaver
2
TryGetValuememberikan nilai default ke parameter nilai keluar jika kunci tidak ada, jadi ini bisa disederhanakan.
Raphael Smit
2
Versi sederhana: TValue public static GetValueOrDefault <TKey, TValue> (Kamus ini <TKey, TValue> dict, kunci TKey) {ret ret TV; dict.TryGetValue (key, out ret); ret ret; }
Joshua
2
Di C # 7 ini benar-benar menyenangkan:if(!dic.TryGetValue(key, out value item)) item = dic[key] = new Item();
Shimmy Weitzhandler
1
Ironisnya, kode sumber asli sudah MEMILIKI rutinitas GetValueOrDefault (), tetapi disembunyikan ... referenceource.microsoft.com/#mscorlib/system/collections/…
Deven T. Corzine
10

Mengapa Anda tidak mengujinya?

Tapi saya cukup yakin itu TryGetValuelebih cepat, karena hanya melakukan satu pencarian. Tentu saja ini tidak dijamin, yaitu implementasi yang berbeda mungkin memiliki karakteristik kinerja yang berbeda.

Cara saya menerapkan kamus adalah dengan membuat Findfungsi internal yang menemukan slot untuk sebuah item, dan kemudian membangun sisanya di atasnya.

CodesInChaos
sumber
Saya tidak berpikir detail implementasi mungkin dapat mengubah jaminan bahwa melakukan tindakan X sekali lebih cepat dari atau sama dengan melakukan tindakan X dua kali. Kasus terbaik mereka identik, kasus terburuk versi 2X memakan waktu dua kali lebih lama.
Dan Bechard
9

Semua jawaban sejauh ini, meskipun bagus, kehilangan satu poin penting.

Metode ke dalam kelas API (misalnya .NET framework) membentuk bagian dari definisi antarmuka (bukan antarmuka C # atau VB, tetapi antarmuka dalam makna ilmu komputer).

Karena itu, biasanya tidak benar untuk bertanya apakah memanggil metode seperti itu lebih cepat, kecuali kecepatan adalah bagian dari definisi antarmuka formal (yang tidak dalam hal ini).

Secara tradisional cara pintas semacam ini (menggabungkan pencarian dan mengambil) lebih efisien terlepas dari bahasa, infrastruktur, OS, platform, atau arsitektur mesin. Ini juga lebih mudah dibaca, karena mengekspresikan maksud Anda secara eksplisit, daripada menyiratkannya (dari struktur kode Anda).

Jadi jawabannya (dari hack lama beruban) pasti 'Ya' (TryGetValue lebih disukai daripada kombinasi ContainsKey dan Item [Dapatkan] untuk mengambil nilai dari Kamus).

Jika Anda berpikir ini terdengar aneh, pikirkan seperti ini: Bahkan jika implementasi TryGetValue, ContainsKey, dan Item [Get] saat ini tidak menghasilkan perbedaan kecepatan, Anda dapat mengasumsikan bahwa kemungkinan implementasi di masa depan (mis. NET v5) akan melakukannya (TryGetValue akan lebih cepat). Pikirkan tentang masa pakai perangkat lunak Anda.

Sebagai tambahan, sangat menarik untuk dicatat bahwa tipikal teknologi definisi antarmuka modern masih jarang memberikan cara mendefinisikan batasan waktu secara formal. Mungkin .NET v5?

pendebat
sumber
2
Sementara saya 100% setuju dengan argumen Anda tentang semantik, masih ada baiknya melakukan tes kinerja. Anda tidak pernah tahu kapan API yang Anda gunakan memiliki implementasi yang kurang optimal sehingga hal yang semantik benar terjadi lebih lambat, kecuali jika Anda melakukan tes.
Dan Bechard
5

Membuat program pengujian cepat, pasti ada peningkatan menggunakan TryGetValue dengan 1 juta item dalam kamus.

Hasil:

ContainsKey + Item untuk 10.00000 hits: 45 ms

TryGetValue for 1000000 hits: 26ms

Ini adalah aplikasi tesnya:

static void Main(string[] args)
{
    const int size = 1000000;

    var dict = new Dictionary<int, string>();

    for (int i = 0; i < size; i++)
    {
        dict.Add(i, i.ToString());
    }

    var sw = new Stopwatch();
    string result;

    sw.Start();

    for (int i = 0; i < size; i++)
    {
        if (dict.ContainsKey(i))
            result = dict[i];
    }

    sw.Stop();
    Console.WriteLine("ContainsKey + Item for {0} hits: {1}ms", size, sw.ElapsedMilliseconds);

    sw.Reset();
    sw.Start();

    for (int i = 0; i < size; i++)
    {
        dict.TryGetValue(i, out result);
    }

    sw.Stop();
    Console.WriteLine("TryGetValue for {0} hits: {1}ms", size, sw.ElapsedMilliseconds);

}
davisoa
sumber
5

Di mesin saya, dengan banyak RAM, ketika dijalankan dalam mode RELEASE (bukan DEBUG), ContainsKeysama dengan TryGetValue/ try-catchjika semua entri dalam Dictionary<>ditemukan.

ContainsKeymengungguli semuanya sejauh ini ketika hanya ada beberapa entri kamus yang tidak ditemukan (dalam contoh saya di bawah ini, atur MAXVALke sesuatu yang lebih besar daripada ENTRIESbeberapa entri yang terlewat):

Hasil:

Finished evaluation .... Time distribution:
Size: 000010: TryGetValue: 53,24%, ContainsKey: 1,74%, try-catch: 45,01% - Total: 2.006,00
Size: 000020: TryGetValue: 37,66%, ContainsKey: 0,53%, try-catch: 61,81% - Total: 2.443,00
Size: 000040: TryGetValue: 22,02%, ContainsKey: 0,73%, try-catch: 77,25% - Total: 7.147,00
Size: 000080: TryGetValue: 31,46%, ContainsKey: 0,42%, try-catch: 68,12% - Total: 17.793,00
Size: 000160: TryGetValue: 33,66%, ContainsKey: 0,37%, try-catch: 65,97% - Total: 36.840,00
Size: 000320: TryGetValue: 34,53%, ContainsKey: 0,39%, try-catch: 65,09% - Total: 71.059,00
Size: 000640: TryGetValue: 32,91%, ContainsKey: 0,32%, try-catch: 66,77% - Total: 141.789,00
Size: 001280: TryGetValue: 39,02%, ContainsKey: 0,35%, try-catch: 60,64% - Total: 244.657,00
Size: 002560: TryGetValue: 35,48%, ContainsKey: 0,19%, try-catch: 64,33% - Total: 420.121,00
Size: 005120: TryGetValue: 43,41%, ContainsKey: 0,24%, try-catch: 56,34% - Total: 625.969,00
Size: 010240: TryGetValue: 29,64%, ContainsKey: 0,61%, try-catch: 69,75% - Total: 1.197.242,00
Size: 020480: TryGetValue: 35,14%, ContainsKey: 0,53%, try-catch: 64,33% - Total: 2.405.821,00
Size: 040960: TryGetValue: 37,28%, ContainsKey: 0,24%, try-catch: 62,48% - Total: 4.200.839,00
Size: 081920: TryGetValue: 29,68%, ContainsKey: 0,54%, try-catch: 69,77% - Total: 8.980.230,00

Ini kode saya:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                const int ENTRIES = 10000, MAXVAL = 15000, TRIALS = 100000, MULTIPLIER = 2;
                Dictionary<int, int> values = new Dictionary<int, int>();
                Random r = new Random();
                int[] lookups = new int[TRIALS];
                int val;
                List<Tuple<long, long, long>> durations = new List<Tuple<long, long, long>>(8);

                for (int i = 0;i < ENTRIES;++i) try
                    {
                        values.Add(r.Next(MAXVAL), r.Next());
                    }
                    catch { --i; }

                for (int i = 0;i < TRIALS;++i) lookups[i] = r.Next(MAXVAL);

                Stopwatch sw = new Stopwatch();
                ConsoleColor bu = Console.ForegroundColor;

                for (int size = 10;size <= TRIALS;size *= MULTIPLIER)
                {
                    long a, b, c;

                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("Loop size: {0}", size);
                    Console.ForegroundColor = bu;

                    // ---------------------------------------------------------------------
                    sw.Start();
                    for (int i = 0;i < size;++i) values.TryGetValue(lookups[i], out val);
                    sw.Stop();
                    Console.WriteLine("TryGetValue: {0}", a = sw.ElapsedTicks);

                    // ---------------------------------------------------------------------
                    sw.Restart();
                    for (int i = 0;i < size;++i) val = values.ContainsKey(lookups[i]) ? values[lookups[i]] : default(int);
                    sw.Stop();
                    Console.WriteLine("ContainsKey: {0}", b = sw.ElapsedTicks);

                    // ---------------------------------------------------------------------
                    sw.Restart();
                    for (int i = 0;i < size;++i)
                        try { val = values[lookups[i]]; }
                        catch { }
                    sw.Stop();
                    Console.WriteLine("try-catch: {0}", c = sw.ElapsedTicks);

                    // ---------------------------------------------------------------------
                    Console.WriteLine();

                    durations.Add(new Tuple<long, long, long>(a, b, c));
                }

                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("Finished evaluation .... Time distribution:");
                Console.ForegroundColor = bu;

                val = 10;
                foreach (Tuple<long, long, long> d in durations)
                {
                    long sum = d.Item1 + d.Item2 + d.Item3;

                    Console.WriteLine("Size: {0:D6}:", val);
                    Console.WriteLine("TryGetValue: {0:P2}, ContainsKey: {1:P2}, try-catch: {2:P2} - Total: {3:N}", (decimal)d.Item1 / sum, (decimal)d.Item2 / sum, (decimal)d.Item3 / sum, sum);
                    val *= MULTIPLIER;
                }

                Console.WriteLine();
            }
        }
    }
AxD
sumber
Saya merasa ada sesuatu yang mencurigakan di sini. Saya ingin tahu apakah pengoptimal mungkin menghapus atau menyederhanakan pemeriksaan ContainsKey () Anda karena Anda tidak pernah menggunakan nilai yang diambil.
Dan Bechard
Itu tidak bisa. ContainsKey () dalam DLL yang dikompilasi. Pengoptimal tidak tahu apa-apa tentang apa yang sebenarnya ContainsKey () lakukan. Ini dapat menyebabkan efek samping, sehingga harus dipanggil dan tidak dapat diringkas.
AxD
Ada yang palsu di sini. Faktanya adalah bahwa memeriksa kode .NET menunjukkan bahwa ContainsKey, TryGetValue, dan ini [] semua memanggil kode internal yang sama, jadi TryGetValue lebih cepat daripada ContainsKey + this [] ketika entri ada.
Jim Balter
3

Selain merancang microbenchmark yang akan memberikan hasil yang akurat dalam pengaturan praktis, Anda dapat memeriksa sumber referensi .NET Framework.

Semua dari mereka memanggil FindEntry(TKey)metode yang melakukan sebagian besar pekerjaan dan tidak menghafal hasilnya, sehingga panggilan TryGetValuehampir dua kali lebih cepat dari ContainsKey+Item .


Antarmuka yang tidak nyaman TryGetValuedapat diadaptasi menggunakan metode ekstensi :

using System.Collections.Generic;

namespace Project.Common.Extensions
{
    public static class DictionaryExtensions
    {
        public static TValue GetValueOrDefault<TKey, TValue>(
            this IDictionary<TKey, TValue> dictionary,
            TKey key,
            TValue defaultValue = default(TValue))
        {
            if (dictionary.TryGetValue(key, out TValue value))
            {
                return value;
            }
            return defaultValue;
        }
    }
}

Karena C # 7.1, Anda dapat mengganti default(TValue)dengan yang biasa default. Jenisnya disimpulkan.

Pemakaian:

var dict = new Dictionary<string, string>();
string val = dict.GetValueOrDefault("theKey", "value used if theKey is not found in dict");

Ini mengembalikan nulluntuk jenis referensi yang pencariannya gagal, kecuali nilai standar eksplisit ditentukan.

var dictObj = new Dictionary<string, object>();
object valObj = dictObj.GetValueOrDefault("nonexistent");
Debug.Assert(valObj == null);

val dictInt = new Dictionary<string, int>();
int valInt = dictInt.GetValueOrDefault("nonexistent");
Debug.Assert(valInt == 0);
Palec
sumber
Perhatikan bahwa pengguna metode ekstensi tidak dapat membedakan antara kunci tidak ada dan kunci yang ada tetapi nilainya default (T).
Lucas
Pada komputer modern, jika Anda memanggil subrutin dua kali berturut-turut dengan cepat, sepertinya tidak perlu dua kali selama memanggilnya sekali. Ini karena arsitektur CPU dan caching sangat mungkin untuk menyimpan banyak instruksi dan data yang terkait dengan panggilan pertama, sehingga panggilan kedua akan dieksekusi lebih cepat. Di sisi lain, menelepon dua kali hampir pasti memakan waktu sedikit lebih lama daripada menelepon sekali, jadi masih ada keuntungan untuk menghilangkan panggilan kedua jika memungkinkan.
pendebat
2

Jika Anda mencoba untuk mendapatkan nilai dari kamus, TryGetValue (kunci, nilai keluar) adalah pilihan terbaik, tetapi jika Anda memeriksa keberadaan kunci, untuk penyisipan baru, tanpa menimpa kunci lama, dan hanya dengan ruang lingkup itu, ContainsKey (kunci) adalah pilihan terbaik, patokan dapat mengkonfirmasi ini:

using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections;

namespace benchmark
{
class Program
{
    public static Random m_Rand = new Random();
    public static Dictionary<int, int> testdict = new Dictionary<int, int>();
    public static Hashtable testhash = new Hashtable();

    public static void Main(string[] args)
    {
        Console.WriteLine("Adding elements into hashtable...");
        Stopwatch watch = Stopwatch.StartNew();
        for(int i=0; i<1000000; i++)
            testhash[i]=m_Rand.Next();
        watch.Stop();
        Console.WriteLine("Done in {0:F4} -- pause....", watch.Elapsed.TotalSeconds);
        Thread.Sleep(4000);
        Console.WriteLine("Adding elements into dictionary...");
        watch = Stopwatch.StartNew();
        for(int i=0; i<1000000; i++)
            testdict[i]=m_Rand.Next();
        watch.Stop();
        Console.WriteLine("Done in {0:F4} -- pause....", watch.Elapsed.TotalSeconds);
        Thread.Sleep(4000);

        Console.WriteLine("Finding the first free number for insertion");
        Console.WriteLine("First method: ContainsKey");
        watch = Stopwatch.StartNew();
        int intero=0;
        while (testdict.ContainsKey(intero))
        {
            intero++;
        }
        testdict.Add(intero, m_Rand.Next());
        watch.Stop();
        Console.WriteLine("Done in {0:F4} -- added value {1} in dictionary -- pause....", watch.Elapsed.TotalSeconds, intero);
        Thread.Sleep(4000);
        Console.WriteLine("Second method: TryGetValue");
        watch = Stopwatch.StartNew();
        intero=0;
        int result=0;
        while(testdict.TryGetValue(intero, out result))
        {
            intero++;
        }
        testdict.Add(intero, m_Rand.Next());
        watch.Stop();
        Console.WriteLine("Done in {0:F4} -- added value {1} in dictionary -- pause....", watch.Elapsed.TotalSeconds, intero);
        Thread.Sleep(4000);
        Console.WriteLine("Test hashtable");
        watch = Stopwatch.StartNew();
        intero=0;
        while(testhash.Contains(intero))
        {
            intero++;
        }
        testhash.Add(intero, m_Rand.Next());
        watch.Stop();
        Console.WriteLine("Done in {0:F4} -- added value {1} into hashtable -- pause....", watch.Elapsed.TotalSeconds, intero);
        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
    }
}
}

Ini adalah Contoh yang benar, saya memiliki layanan yang untuk setiap "Item" yang dibuat, itu mengaitkan angka progresif, nomor ini, setiap kali Anda membuat item baru, harus ditemukan gratis, jika Anda menghapus Item, nomor bebas menjadi gratis, tentu saja ini tidak dioptimalkan, karena saya memiliki var statis yang menyimpan nomor saat ini, tetapi jika Anda mengakhiri semua angka, Anda dapat memulai kembali dari 0 hingga UInt32.MaxValue

Uji dieksekusi:
Menambahkan elemen ke
hashtabel ... Dilakukan di 0,5908 - jeda ....
Menambahkan elemen ke kamus ...
Selesai dalam 0,2679 - jeda ....
Menemukan nomor bebas pertama untuk penyisipan
Metode pertama : ContainsKey
Done in 0,0561 - nilai tambah 1000000 dalam kamus - jeda ....
Metode kedua: TryGetValue
Done in 0,0643 - nilai tambah 1000001 dalam kamus - jeda ....
Uji hashtable
Selesai dalam 0, 3015 - nilai tambah 1000000 ke dalam hashtable - pause ....
Tekan sembarang tombol untuk melanjutkan. .

Jika beberapa dari Anda mungkin bertanya apakah ContainsKeys dapat memiliki keuntungan, saya bahkan sudah mencoba membalikkan kunci TryGetValue with Contains, hasilnya sama.

Jadi, bagi saya, dengan pertimbangan akhir, semuanya tergantung pada cara program itu bertindak.

Fwiffo
sumber