{"id":341154,"date":"2023-04-18T14:58:19","date_gmt":"2023-04-18T13:58:19","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=dotnet&#038;p=341154"},"modified":"2023-04-20T09:42:58","modified_gmt":"2023-04-20T08:42:58","slug":"reduce-lookups-in-hashset-dictionary-and-other-collections-with-resharper","status":"publish","type":"dotnet","link":"https:\/\/blog.jetbrains.com\/zh-hans\/dotnet\/2023\/04\/18\/reduce-lookups-in-hashset-dictionary-and-other-collections-with-resharper","title":{"rendered":"Reduce Collection Lookups With ReSharper"},"content":{"rendered":"\n<p><strong>The 2023.1 <a href=\"https:\/\/www.jetbrains.com\/resharper\/\" target=\"_blank\" rel=\"noopener\">ReSharper<\/a> and <a href=\"https:\/\/www.jetbrains.com\/rider\/\" target=\"_blank\" rel=\"noopener\">JetBrains Rider<\/a> releases<\/strong> introduce a set of inspections and quick-fixes that <strong>help you optimize and speed up your code when working with different collections.<\/strong><\/p>\n\n\n\n<p>Many C# projects contain numerous places where developers add items to collections like <code>HashSet<\/code> and <code>Dictionary<\/code>. Quite often, there\u2019s a check to verify whether the item is already in the collection. However, this may be quite wasteful, as the <code>Add()<\/code> and <code>TryAdd()<\/code> methods on these collections already do that check for you \u2013 occupying the CPU with the same instructions twice!<\/p>\n\n\n\n<p> Let\u2019s look at some examples!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Working with HashSet&lt;T&gt;<\/h2>\n\n\n\n<p>When writing code using <code>HashSet&lt;T&gt;<\/code>, there\u2019s a good chance your code uses the following pattern. For example, this snippet checks whether the <code>person<\/code> is part of the <code>people<\/code> hashset and only adds the <code>person<\/code> if it\u2019s absent.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"wpcustom\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var person = new Person(\"Maarten\", \"Balliauw\");\nif (!people.Contains(person))\n{\n    people.Add(person);\n}<\/pre>\n\n\n\n<p>You don\u2019t have to check if an item is already in a <code>HashSet&lt;T&gt;<\/code> using the <code>Contains()<\/code> method! If you look at the <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/50c1214f049424a7ba0080626b7f07e675b34f8b\/src\/libraries\/System.Private.CoreLib\/src\/System\/Collections\/Generic\/HashSet.cs\" target=\"_blank\" rel=\"noopener\">source code for <code>HashSet&lt;T&gt;<\/code><\/a>, you\u2019ll see both <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/50c1214f049424a7ba0080626b7f07e675b34f8b\/src\/libraries\/System.Private.CoreLib\/src\/System\/Collections\/Generic\/HashSet.cs#L210\" target=\"_blank\" rel=\"noopener\"><code>Contains()<\/code><\/a> and <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/50c1214f049424a7ba0080626b7f07e675b34f8b\/src\/libraries\/System.Private.CoreLib\/src\/System\/Collections\/Generic\/HashSet.cs#L188\" target=\"_blank\" rel=\"noopener\"><code>Add()<\/code><\/a> check whether the hashset contains an item. In other words, you\u2019re doing the same operation twice.<\/p>\n\n\n\n<p>If you are doing this \u201ccontains check\u201d occasionally, and on small collections, the performance impact of running the check will be minimal. However, you can reduce CPU time by using only <code>Add()<\/code> when doing this often with more significant collections. These situations are where ReSharper and JetBrains Rider can help you!<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"504\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/04\/image-1.png\" alt=\"\" class=\"wp-image-341205\"\/><\/figure>\n\n\n\n<p>A new inspection informs you about this redundant check, and provides a <strong>Remove redundant .Contains<\/strong> quick-fix that can automatically remove this check. And as with many quick-fixes, you can update the usage of this pattern in our entire project or solution in one go.<\/p>\n\n\n\n<p>Note that ReSharper and JetBrains Rider make these inspections and quick-fixes available on <code>HashSet&lt;T&gt;<\/code> and other types that implement <code>ISet<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Working with Dictionary&lt;TKey, TValue&gt;<\/h2>\n\n\n\n<p>When working with a <code>Dictionary<\/code> instance, a similar inspection and quick-fix is available when using a combination of <code>ContainsKey()<\/code> and <code>Add()<\/code>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"wpcustom\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">if (employees.ContainsKey(id))\n{\n    employees[id] = employee;\n}\nelse\n{\n    employees.Add(id, employee);\n}<\/pre>\n\n\n\n<p>When <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/50c1214f049424a7ba0080626b7f07e675b34f8b\/src\/libraries\/System.Private.CoreLib\/src\/System\/Collections\/Generic\/Dictionary.cs#L212\" target=\"_blank\" rel=\"noopener\">using a dictionary\u2019s indexer<\/a> to set a value, the <code>TryInsert()<\/code> method is used internally to add or update the entry in the dictionary. The <strong>Remove redundant .ContainsKey<\/strong> quick-fix can update your code in one go:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1321\" height=\"460\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/04\/image-2.png\" alt=\"\" class=\"wp-image-341216\"\/><\/figure>\n\n\n\n<p>There are some additional inspections when working with dictionaries. Another common pattern is adding an entry only when its key is not yet present in the dictionary:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"wpcustom\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">if (!employees.ContainsKey(id))\n{\n    employees.Add(id, employee);\n}<\/pre>\n\n\n\n<p>Also, ReSharper and JetBrains Rider come with a suggestion: <code>Dictionary<\/code> and&nbsp; <code>Dictionary&lt;TKey, TValue&gt;<\/code> have a <code>TryAdd()<\/code> method, which does the same. Using the <strong>Simplify with TryAdd<\/strong> quick-fix, you can reduce the number of lookups from 2 to just 1.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"367\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/04\/image-3.png\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/04\/image.gif\" alt=\"\" class=\"wp-image-341238\"\/><\/figure>\n\n\n\n<p>A similar inspection and quick-fix is available to encourage the use of <code>TryGetValue(key, out value)<\/code> for <code>IDictionary<\/code> collections. The <strong>Simplify with TryGetValue<\/strong> quick-fix again removes one lookup in such a situation. Here\u2019s a before and after:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"wpcustom\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Before:\nif (employees.ContainsKey(id))\n{\n    return employees[id];\n}\n\n\/\/ After:\nif (employees.TryGetValue(id, out var employee))\n{\n    return employee;\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>ReSharper and JetBrains Rider come with a set of inspections and corresponding quick-fixes to optimize your work with different types of collections by reducing the number of lookups in collections. Especially when working with larger collections or frequently adding entries, optimizing the usage pattern will improve the performance of your code.<\/p>\n\n\n\n<p><a href=\"https:\/\/www.jetbrains.com\/resharper\/download\/\" target=\"_blank\" rel=\"noopener\"><strong>Try the latest ReSharper<\/strong><\/a><strong> <\/strong> or <a href=\"https:\/\/www.jetbrains.com\/rider\/download\/\" target=\"_blank\" rel=\"noopener\"><strong>download JetBrains Rider<\/strong><\/a>! Let us know what you think of these new inspections.<\/p>\n","protected":false},"author":118,"featured_media":341182,"comment_status":"closed","ping_status":"closed","template":"","categories":[4992,1401],"tags":[211,756,46,1978],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/dotnet\/341154"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/dotnet"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/types\/dotnet"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/users\/118"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/comments?post=341154"}],"version-history":[{"count":10,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/dotnet\/341154\/revisions"}],"predecessor-version":[{"id":343744,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/dotnet\/341154\/revisions\/343744"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media\/341182"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media?parent=341154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/categories?post=341154"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/tags?post=341154"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/cross-post-tag?post=341154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}