MapFieldTest.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2015 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. #endregion
  32. using System;
  33. using System.Collections.Generic;
  34. using Google.Protobuf.TestProtos;
  35. using NUnit.Framework;
  36. using System.Collections;
  37. using System.Linq;
  38. namespace Google.Protobuf.Collections
  39. {
  40. /// <summary>
  41. /// Tests for MapField which aren't reliant on the encoded format -
  42. /// tests for serialization/deserialization are part of GeneratedMessageTest.
  43. /// </summary>
  44. public class MapFieldTest
  45. {
  46. [Test]
  47. public void Clone_ClonesMessages()
  48. {
  49. var message = new ForeignMessage { C = 20 };
  50. var map = new MapField<string, ForeignMessage> { { "x", message } };
  51. var clone = map.Clone();
  52. map["x"].C = 30;
  53. Assert.AreEqual(20, clone["x"].C);
  54. }
  55. [Test]
  56. public void NullValues()
  57. {
  58. TestNullValues<int?>(0);
  59. TestNullValues("");
  60. TestNullValues(new TestAllTypes());
  61. }
  62. private void TestNullValues<T>(T nonNullValue)
  63. {
  64. var map = new MapField<int, T>(false);
  65. var nullValue = (T) (object) null;
  66. Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
  67. Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
  68. map.Add(1, nonNullValue);
  69. map[1] = nonNullValue;
  70. // Doesn't throw...
  71. map = new MapField<int, T>(true);
  72. map.Add(0, nullValue);
  73. map[0] = nullValue;
  74. map.Add(1, nonNullValue);
  75. map[1] = nonNullValue;
  76. }
  77. [Test]
  78. public void Add_ForbidsNullKeys()
  79. {
  80. var map = new MapField<string, ForeignMessage>();
  81. Assert.Throws<ArgumentNullException>(() => map.Add(null, new ForeignMessage()));
  82. }
  83. [Test]
  84. public void Indexer_ForbidsNullKeys()
  85. {
  86. var map = new MapField<string, ForeignMessage>();
  87. Assert.Throws<ArgumentNullException>(() => map[null] = new ForeignMessage());
  88. }
  89. [Test]
  90. public void AddPreservesInsertionOrder()
  91. {
  92. var map = new MapField<string, string>();
  93. map.Add("a", "v1");
  94. map.Add("b", "v2");
  95. map.Add("c", "v3");
  96. map.Remove("b");
  97. map.Add("d", "v4");
  98. CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);
  99. CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);
  100. }
  101. [Test]
  102. public void EqualityIsOrderInsensitive()
  103. {
  104. var map1 = new MapField<string, string>();
  105. map1.Add("a", "v1");
  106. map1.Add("b", "v2");
  107. var map2 = new MapField<string, string>();
  108. map2.Add("b", "v2");
  109. map2.Add("a", "v1");
  110. EqualityTester.AssertEquality(map1, map2);
  111. }
  112. [Test]
  113. public void EqualityIsKeySensitive()
  114. {
  115. var map1 = new MapField<string, string>();
  116. map1.Add("first key", "v1");
  117. map1.Add("second key", "v2");
  118. var map2 = new MapField<string, string>();
  119. map2.Add("third key", "v1");
  120. map2.Add("fourth key", "v2");
  121. EqualityTester.AssertInequality(map1, map2);
  122. }
  123. [Test]
  124. public void Equality_Simple()
  125. {
  126. var map = new MapField<string, string>();
  127. EqualityTester.AssertEquality(map, map);
  128. EqualityTester.AssertInequality(map, null);
  129. Assert.IsFalse(map.Equals(new object()));
  130. }
  131. [Test]
  132. public void EqualityIsValueSensitive()
  133. {
  134. // Note: Without some care, it's a little easier than one might
  135. // hope to see hash collisions, but only in some environments...
  136. var map1 = new MapField<string, string>();
  137. map1.Add("a", "first value");
  138. map1.Add("b", "second value");
  139. var map2 = new MapField<string, string>();
  140. map2.Add("a", "third value");
  141. map2.Add("b", "fourth value");
  142. EqualityTester.AssertInequality(map1, map2);
  143. }
  144. [Test]
  145. public void EqualityHandlesNullValues()
  146. {
  147. var map1 = new MapField<string, ForeignMessage>();
  148. map1.Add("a", new ForeignMessage { C = 10 });
  149. map1.Add("b", null);
  150. var map2 = new MapField<string, ForeignMessage>();
  151. map2.Add("a", new ForeignMessage { C = 10 });
  152. map2.Add("b", null);
  153. EqualityTester.AssertEquality(map1, map2);
  154. // Check the null value isn't ignored entirely...
  155. Assert.IsTrue(map1.Remove("b"));
  156. EqualityTester.AssertInequality(map1, map2);
  157. map1.Add("b", new ForeignMessage());
  158. EqualityTester.AssertInequality(map1, map2);
  159. map1["b"] = null;
  160. EqualityTester.AssertEquality(map1, map2);
  161. }
  162. [Test]
  163. public void Add_Dictionary()
  164. {
  165. var map1 = new MapField<string, string>
  166. {
  167. { "x", "y" },
  168. { "a", "b" }
  169. };
  170. var map2 = new MapField<string, string>
  171. {
  172. { "before", "" },
  173. map1,
  174. { "after", "" }
  175. };
  176. var expected = new MapField<string, string>
  177. {
  178. { "before", "" },
  179. { "x", "y" },
  180. { "a", "b" },
  181. { "after", "" }
  182. };
  183. Assert.AreEqual(expected, map2);
  184. CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);
  185. }
  186. // General IDictionary<TKey, TValue> behavior tests
  187. [Test]
  188. public void Add_KeyAlreadyExists()
  189. {
  190. var map = new MapField<string, string>();
  191. map.Add("foo", "bar");
  192. Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));
  193. }
  194. [Test]
  195. public void Add_Pair()
  196. {
  197. var map = new MapField<string, string>();
  198. ICollection<KeyValuePair<string, string>> collection = map;
  199. collection.Add(NewKeyValuePair("x", "y"));
  200. Assert.AreEqual("y", map["x"]);
  201. Assert.Throws<ArgumentException>(() => collection.Add(NewKeyValuePair("x", "z")));
  202. }
  203. [Test]
  204. public void Contains_Pair()
  205. {
  206. var map = new MapField<string, string> { { "x", "y" } };
  207. ICollection<KeyValuePair<string, string>> collection = map;
  208. Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));
  209. Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));
  210. Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));
  211. }
  212. [Test]
  213. public void Remove_Key()
  214. {
  215. var map = new MapField<string, string>();
  216. map.Add("foo", "bar");
  217. Assert.AreEqual(1, map.Count);
  218. Assert.IsFalse(map.Remove("missing"));
  219. Assert.AreEqual(1, map.Count);
  220. Assert.IsTrue(map.Remove("foo"));
  221. Assert.AreEqual(0, map.Count);
  222. Assert.Throws<ArgumentNullException>(() => map.Remove(null));
  223. }
  224. [Test]
  225. public void Remove_Pair()
  226. {
  227. var map = new MapField<string, string>();
  228. map.Add("foo", "bar");
  229. ICollection<KeyValuePair<string, string>> collection = map;
  230. Assert.AreEqual(1, map.Count);
  231. Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));
  232. Assert.AreEqual(1, map.Count);
  233. Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));
  234. Assert.AreEqual(1, map.Count);
  235. Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));
  236. Assert.AreEqual(0, map.Count);
  237. Assert.Throws<ArgumentException>(() => collection.Remove(new KeyValuePair<string, string>(null, "")));
  238. }
  239. [Test]
  240. public void CopyTo_Pair()
  241. {
  242. var map = new MapField<string, string>();
  243. map.Add("foo", "bar");
  244. ICollection<KeyValuePair<string, string>> collection = map;
  245. KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[3];
  246. collection.CopyTo(array, 1);
  247. Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);
  248. }
  249. [Test]
  250. public void Clear()
  251. {
  252. var map = new MapField<string, string> { { "x", "y" } };
  253. Assert.AreEqual(1, map.Count);
  254. map.Clear();
  255. Assert.AreEqual(0, map.Count);
  256. map.Add("x", "y");
  257. Assert.AreEqual(1, map.Count);
  258. }
  259. [Test]
  260. public void Indexer_Get()
  261. {
  262. var map = new MapField<string, string> { { "x", "y" } };
  263. Assert.AreEqual("y", map["x"]);
  264. Assert.Throws<KeyNotFoundException>(() => { var ignored = map["z"]; });
  265. }
  266. [Test]
  267. public void Indexer_Set()
  268. {
  269. var map = new MapField<string, string>();
  270. map["x"] = "y";
  271. Assert.AreEqual("y", map["x"]);
  272. map["x"] = "z"; // This won't throw, unlike Add.
  273. Assert.AreEqual("z", map["x"]);
  274. }
  275. [Test]
  276. public void GetEnumerator_NonGeneric()
  277. {
  278. IEnumerable map = new MapField<string, string> { { "x", "y" } };
  279. CollectionAssert.AreEqual(new[] { new KeyValuePair<string, string>("x", "y") },
  280. map.Cast<object>().ToList());
  281. }
  282. // Test for the explicitly-implemented non-generic IDictionary interface
  283. [Test]
  284. public void IDictionary_GetEnumerator()
  285. {
  286. IDictionary map = new MapField<string, string> { { "x", "y" } };
  287. var enumerator = map.GetEnumerator();
  288. // Commented assertions show an ideal situation - it looks like
  289. // the LinkedList enumerator doesn't throw when you ask for the current entry
  290. // at an inappropriate time; fixing this would be more work than it's worth.
  291. // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
  292. Assert.IsTrue(enumerator.MoveNext());
  293. Assert.AreEqual("x", enumerator.Key);
  294. Assert.AreEqual("y", enumerator.Value);
  295. Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Current);
  296. Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Entry);
  297. Assert.IsFalse(enumerator.MoveNext());
  298. // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
  299. enumerator.Reset();
  300. // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
  301. Assert.IsTrue(enumerator.MoveNext());
  302. Assert.AreEqual("x", enumerator.Key); // Assume the rest are okay
  303. }
  304. [Test]
  305. public void IDictionary_Add()
  306. {
  307. var map = new MapField<string, string> { { "x", "y" } };
  308. IDictionary dictionary = map;
  309. dictionary.Add("a", "b");
  310. Assert.AreEqual("b", map["a"]);
  311. Assert.Throws<ArgumentException>(() => dictionary.Add("a", "duplicate"));
  312. Assert.Throws<InvalidCastException>(() => dictionary.Add(new object(), "key is bad"));
  313. Assert.Throws<InvalidCastException>(() => dictionary.Add("value is bad", new object()));
  314. }
  315. [Test]
  316. public void IDictionary_Contains()
  317. {
  318. var map = new MapField<string, string> { { "x", "y" } };
  319. IDictionary dictionary = map;
  320. Assert.IsFalse(dictionary.Contains("a"));
  321. Assert.IsFalse(dictionary.Contains(5));
  322. // Surprising, but IDictionary.Contains is only about keys.
  323. Assert.IsFalse(dictionary.Contains(new DictionaryEntry("x", "y")));
  324. Assert.IsTrue(dictionary.Contains("x"));
  325. }
  326. [Test]
  327. public void IDictionary_Remove()
  328. {
  329. var map = new MapField<string, string> { { "x", "y" } };
  330. IDictionary dictionary = map;
  331. dictionary.Remove("a");
  332. Assert.AreEqual(1, dictionary.Count);
  333. dictionary.Remove(5);
  334. Assert.AreEqual(1, dictionary.Count);
  335. dictionary.Remove(new DictionaryEntry("x", "y"));
  336. Assert.AreEqual(1, dictionary.Count);
  337. dictionary.Remove("x");
  338. Assert.AreEqual(0, dictionary.Count);
  339. Assert.Throws<ArgumentNullException>(() => dictionary.Remove(null));
  340. }
  341. [Test]
  342. public void IDictionary_CopyTo()
  343. {
  344. var map = new MapField<string, string> { { "x", "y" } };
  345. IDictionary dictionary = map;
  346. var array = new DictionaryEntry[3];
  347. dictionary.CopyTo(array, 1);
  348. CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },
  349. array);
  350. var objectArray = new object[3];
  351. dictionary.CopyTo(objectArray, 1);
  352. CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },
  353. objectArray);
  354. }
  355. [Test]
  356. public void IDictionary_IsFixedSize()
  357. {
  358. var map = new MapField<string, string> { { "x", "y" } };
  359. IDictionary dictionary = map;
  360. Assert.IsFalse(dictionary.IsFixedSize);
  361. }
  362. [Test]
  363. public void IDictionary_Keys()
  364. {
  365. IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
  366. CollectionAssert.AreEqual(new[] { "x" }, dictionary.Keys);
  367. }
  368. [Test]
  369. public void IDictionary_Values()
  370. {
  371. IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
  372. CollectionAssert.AreEqual(new[] { "y" }, dictionary.Values);
  373. }
  374. [Test]
  375. public void IDictionary_IsSynchronized()
  376. {
  377. IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
  378. Assert.IsFalse(dictionary.IsSynchronized);
  379. }
  380. [Test]
  381. public void IDictionary_SyncRoot()
  382. {
  383. IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
  384. Assert.AreSame(dictionary, dictionary.SyncRoot);
  385. }
  386. [Test]
  387. public void IDictionary_Indexer_Get()
  388. {
  389. IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
  390. Assert.AreEqual("y", dictionary["x"]);
  391. Assert.IsNull(dictionary["a"]);
  392. Assert.IsNull(dictionary[5]);
  393. Assert.Throws<ArgumentNullException>(() => dictionary[null].GetHashCode());
  394. }
  395. [Test]
  396. public void IDictionary_Indexer_Set()
  397. {
  398. var map = new MapField<string, string> { { "x", "y" } };
  399. IDictionary dictionary = map;
  400. map["a"] = "b";
  401. Assert.AreEqual("b", map["a"]);
  402. map["a"] = "c";
  403. Assert.AreEqual("c", map["a"]);
  404. Assert.Throws<InvalidCastException>(() => dictionary[5] = "x");
  405. Assert.Throws<InvalidCastException>(() => dictionary["x"] = 5);
  406. Assert.Throws<ArgumentNullException>(() => dictionary[null] = "z");
  407. Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);
  408. }
  409. [Test]
  410. public void AllowNullValues_Property()
  411. {
  412. // Non-message reference type values are non-nullable by default, but can be overridden
  413. Assert.IsFalse(new MapField<int, string>().AllowsNullValues);
  414. Assert.IsFalse(new MapField<int, string>(false).AllowsNullValues);
  415. Assert.IsTrue(new MapField<int, string>(true).AllowsNullValues);
  416. // Non-nullable value type values are never nullable
  417. Assert.IsFalse(new MapField<int, int>().AllowsNullValues);
  418. Assert.IsFalse(new MapField<int, int>(false).AllowsNullValues);
  419. Assert.Throws<ArgumentException>(() => new MapField<int, int>(true));
  420. // Message type values are nullable by default, but can be overridden
  421. Assert.IsTrue(new MapField<int, TestAllTypes>().AllowsNullValues);
  422. Assert.IsFalse(new MapField<int, TestAllTypes>(false).AllowsNullValues);
  423. Assert.IsTrue(new MapField<int, TestAllTypes>(true).AllowsNullValues);
  424. // Nullable value type values are nullable by default, but can be overridden
  425. Assert.IsTrue(new MapField<int, int?>().AllowsNullValues);
  426. Assert.IsFalse(new MapField<int, int?>(false).AllowsNullValues);
  427. Assert.IsTrue(new MapField<int, int?>(true).AllowsNullValues);
  428. }
  429. [Test]
  430. public void KeysReturnsLiveView()
  431. {
  432. var map = new MapField<string, string>();
  433. var keys = map.Keys;
  434. CollectionAssert.AreEqual(new string[0], keys);
  435. map["foo"] = "bar";
  436. map["x"] = "y";
  437. CollectionAssert.AreEqual(new[] { "foo", "x" }, keys);
  438. }
  439. [Test]
  440. public void ValuesReturnsLiveView()
  441. {
  442. var map = new MapField<string, string>();
  443. var values = map.Values;
  444. CollectionAssert.AreEqual(new string[0], values);
  445. map["foo"] = "bar";
  446. map["x"] = "y";
  447. CollectionAssert.AreEqual(new[] { "bar", "y" }, values);
  448. }
  449. // Just test keys - we know the implementation is the same for values
  450. [Test]
  451. public void ViewsAreReadOnly()
  452. {
  453. var map = new MapField<string, string>();
  454. var keys = map.Keys;
  455. Assert.IsTrue(keys.IsReadOnly);
  456. Assert.Throws<NotSupportedException>(() => keys.Clear());
  457. Assert.Throws<NotSupportedException>(() => keys.Remove("a"));
  458. Assert.Throws<NotSupportedException>(() => keys.Add("a"));
  459. }
  460. // Just test keys - we know the implementation is the same for values
  461. [Test]
  462. public void ViewCopyTo()
  463. {
  464. var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
  465. var keys = map.Keys;
  466. var array = new string[4];
  467. Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
  468. Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
  469. keys.CopyTo(array, 1);
  470. CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
  471. }
  472. // Just test keys - we know the implementation is the same for values
  473. [Test]
  474. public void NonGenericViewCopyTo()
  475. {
  476. IDictionary map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
  477. ICollection keys = map.Keys;
  478. // Note the use of the Array type here rather than string[]
  479. Array array = new string[4];
  480. Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
  481. Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
  482. keys.CopyTo(array, 1);
  483. CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
  484. }
  485. [Test]
  486. public void KeysContains()
  487. {
  488. var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
  489. var keys = map.Keys;
  490. Assert.IsTrue(keys.Contains("foo"));
  491. Assert.IsFalse(keys.Contains("bar")); // It's a value!
  492. Assert.IsFalse(keys.Contains("1"));
  493. // Keys can't be null, so we should prevent contains check
  494. Assert.Throws<ArgumentNullException>(() => keys.Contains(null));
  495. }
  496. [Test]
  497. public void ValuesContains()
  498. {
  499. var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
  500. var values = map.Values;
  501. Assert.IsTrue(values.Contains("bar"));
  502. Assert.IsFalse(values.Contains("foo")); // It's a key!
  503. Assert.IsFalse(values.Contains("1"));
  504. // Values can be null, so this makes sense
  505. Assert.IsFalse(values.Contains(null));
  506. }
  507. private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
  508. {
  509. return new KeyValuePair<TKey, TValue>(key, value);
  510. }
  511. }
  512. }