Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 92cc266

Browse files
authored
Merge pull request #32001 from iSazonov/fix-ordereddictionary
Exclude extra allocations in OrderedDictionary
2 parents f024dd1 + 5670a43 commit 92cc266

File tree

1 file changed

+91
-49
lines changed

1 file changed

+91
-49
lines changed

src/System.Collections.Specialized/src/System/Collections/Specialized/OrderedDictionary.cs

Lines changed: 91 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace System.Collections.Specialized
1515
/// OrderedDictionary is used by the ParameterCollection because MSAccess relies on ordering of
1616
/// parameters, while almost all other DBs do not. DataKeyArray also uses it so
1717
/// DataKeys can be retrieved by either their name or their index.
18-
///
18+
///
1919
/// OrderedDictionary implements IDeserializationCallback because it needs to have the
2020
/// contained ArrayList and Hashtable deserialized before it tries to get its count and objects.
2121
/// </para>
@@ -69,7 +69,7 @@ private OrderedDictionary(OrderedDictionary dictionary)
6969
protected OrderedDictionary(SerializationInfo info, StreamingContext context)
7070
{
7171
// We can't do anything with the keys and values until the entire graph has been deserialized
72-
// and getting Counts and objects won't fail. For the time being, we'll just cache this.
72+
// and getting Counts and objects won't fail. For the time being, we'll just cache this.
7373
// The graph is not valid until OnDeserialization has been called.
7474
_siInfo = info;
7575
}
@@ -81,7 +81,11 @@ public int Count
8181
{
8282
get
8383
{
84-
return objectsArray.Count;
84+
if (_objectsArray == null)
85+
{
86+
return 0;
87+
}
88+
return _objectsArray.Count;
8589
}
8690
}
8791

@@ -125,31 +129,24 @@ public ICollection Keys
125129
{
126130
get
127131
{
128-
return new OrderedDictionaryKeyValueCollection(objectsArray, true);
132+
EnsureObjectsArray();
133+
return new OrderedDictionaryKeyValueCollection(_objectsArray, true);
129134
}
130135
}
131136

132-
private ArrayList objectsArray
137+
private void EnsureObjectsArray()
133138
{
134-
get
139+
if (_objectsArray == null)
135140
{
136-
if (_objectsArray == null)
137-
{
138-
_objectsArray = new ArrayList(_initialCapacity);
139-
}
140-
return _objectsArray;
141+
_objectsArray = new ArrayList(_initialCapacity);
141142
}
142143
}
143144

144-
private Hashtable objectsTable
145+
private void EnsureObjectsTable()
145146
{
146-
get
147+
if (_objectsTable == null)
147148
{
148-
if (_objectsTable == null)
149-
{
150-
_objectsTable = new Hashtable(_initialCapacity, _comparer);
151-
}
152-
return _objectsTable;
149+
_objectsTable = new Hashtable(_initialCapacity, _comparer);
153150
}
154151
}
155152

@@ -175,21 +172,27 @@ public object this[int index]
175172
{
176173
get
177174
{
178-
return ((DictionaryEntry)objectsArray[index]).Value;
175+
if (_objectsArray == null)
176+
{
177+
throw new ArgumentOutOfRangeException(nameof(index));
178+
}
179+
return ((DictionaryEntry)_objectsArray[index]).Value;
179180
}
180181
set
181182
{
182183
if (_readOnly)
183184
{
184185
throw new NotSupportedException(SR.OrderedDictionary_ReadOnly);
185186
}
186-
if (index < 0 || index >= objectsArray.Count)
187+
if (_objectsArray == null || index < 0 || index >= _objectsArray.Count)
187188
{
188189
throw new ArgumentOutOfRangeException(nameof(index));
189190
}
190-
object key = ((DictionaryEntry)objectsArray[index]).Key;
191-
objectsArray[index] = new DictionaryEntry(key, value);
192-
objectsTable[key] = value;
191+
EnsureObjectsArray();
192+
EnsureObjectsTable();
193+
object key = ((DictionaryEntry)_objectsArray[index]).Key;
194+
_objectsArray[index] = new DictionaryEntry(key, value);
195+
_objectsTable[key] = value;
193196
}
194197
}
195198

@@ -200,18 +203,24 @@ public object this[object key]
200203
{
201204
get
202205
{
203-
return objectsTable[key];
206+
if (_objectsTable == null)
207+
{
208+
return null;
209+
}
210+
return _objectsTable[key];
204211
}
205212
set
206213
{
207214
if (_readOnly)
208215
{
209216
throw new NotSupportedException(SR.OrderedDictionary_ReadOnly);
210217
}
211-
if (objectsTable.Contains(key))
218+
EnsureObjectsTable();
219+
if (_objectsTable.Contains(key))
212220
{
213-
objectsTable[key] = value;
214-
objectsArray[IndexOfKey(key)] = new DictionaryEntry(key, value);
221+
_objectsTable[key] = value;
222+
EnsureObjectsArray();
223+
_objectsArray[IndexOfKey(key)] = new DictionaryEntry(key, value);
215224
}
216225
else
217226
{
@@ -227,7 +236,8 @@ public ICollection Values
227236
{
228237
get
229238
{
230-
return new OrderedDictionaryKeyValueCollection(objectsArray, false);
239+
EnsureObjectsArray();
240+
return new OrderedDictionaryKeyValueCollection(_objectsArray, false);
231241
}
232242
}
233243

@@ -240,8 +250,10 @@ public void Add(object key, object value)
240250
{
241251
throw new NotSupportedException(SR.OrderedDictionary_ReadOnly);
242252
}
243-
objectsTable.Add(key, value);
244-
objectsArray.Add(new DictionaryEntry(key, value));
253+
EnsureObjectsTable();
254+
EnsureObjectsArray();
255+
_objectsTable.Add(key, value);
256+
_objectsArray.Add(new DictionaryEntry(key, value));
245257
}
246258

247259
/// <devdoc>
@@ -253,8 +265,14 @@ public void Clear()
253265
{
254266
throw new NotSupportedException(SR.OrderedDictionary_ReadOnly);
255267
}
256-
objectsTable.Clear();
257-
objectsArray.Clear();
268+
if (_objectsTable != null)
269+
{
270+
_objectsTable.Clear();
271+
}
272+
if (_objectsArray != null)
273+
{
274+
_objectsArray.Clear();
275+
}
258276
}
259277

260278
/// <devdoc>
@@ -270,22 +288,35 @@ public OrderedDictionary AsReadOnly()
270288
/// </devdoc>
271289
public bool Contains(object key)
272290
{
273-
return objectsTable.Contains(key);
291+
if (key == null)
292+
{
293+
throw new ArgumentNullException(nameof(key));
294+
}
295+
if (_objectsTable == null)
296+
{
297+
return false;
298+
}
299+
return _objectsTable.Contains(key);
274300
}
275301

276302
/// <devdoc>
277303
/// Copies the table to an array. This will not preserve order.
278304
/// </devdoc>
279305
public void CopyTo(Array array, int index)
280306
{
281-
objectsTable.CopyTo(array, index);
307+
EnsureObjectsTable();
308+
_objectsTable.CopyTo(array, index);
282309
}
283310

284311
private int IndexOfKey(object key)
285312
{
286-
for (int i = 0; i < objectsArray.Count; i++)
313+
if (_objectsArray == null)
314+
{
315+
return -1;
316+
}
317+
for (int i = 0; i < _objectsArray.Count; i++)
287318
{
288-
object o = ((DictionaryEntry)objectsArray[i]).Key;
319+
object o = ((DictionaryEntry)_objectsArray[i]).Key;
289320
if (_comparer != null)
290321
{
291322
if (_comparer.Equals(o, key))
@@ -317,8 +348,10 @@ public void Insert(int index, object key, object value)
317348
{
318349
throw new ArgumentOutOfRangeException(nameof(index));
319350
}
320-
objectsTable.Add(key, value);
321-
objectsArray.Insert(index, new DictionaryEntry(key, value));
351+
EnsureObjectsTable();
352+
EnsureObjectsArray();
353+
_objectsTable.Add(key, value);
354+
_objectsArray.Insert(index, new DictionaryEntry(key, value));
322355
}
323356

324357
/// <devdoc>
@@ -334,9 +367,11 @@ public void RemoveAt(int index)
334367
{
335368
throw new ArgumentOutOfRangeException(nameof(index));
336369
}
337-
object key = ((DictionaryEntry)objectsArray[index]).Key;
338-
objectsArray.RemoveAt(index);
339-
objectsTable.Remove(key);
370+
EnsureObjectsTable();
371+
EnsureObjectsArray();
372+
object key = ((DictionaryEntry)_objectsArray[index]).Key;
373+
_objectsArray.RemoveAt(index);
374+
_objectsTable.Remove(key);
340375
}
341376

342377
/// <devdoc>
@@ -359,25 +394,29 @@ public void Remove(object key)
359394
return;
360395
}
361396

362-
objectsTable.Remove(key);
363-
objectsArray.RemoveAt(index);
397+
EnsureObjectsTable();
398+
EnsureObjectsArray();
399+
_objectsTable.Remove(key);
400+
_objectsArray.RemoveAt(index);
364401
}
365402

366403
#region IDictionary implementation
367404
public virtual IDictionaryEnumerator GetEnumerator()
368405
{
369-
return new OrderedDictionaryEnumerator(objectsArray, OrderedDictionaryEnumerator.DictionaryEntry);
406+
EnsureObjectsArray();
407+
return new OrderedDictionaryEnumerator(_objectsArray, OrderedDictionaryEnumerator.DictionaryEntry);
370408
}
371409
#endregion
372410

373411
#region IEnumerable implementation
374412
IEnumerator IEnumerable.GetEnumerator()
375413
{
376-
return new OrderedDictionaryEnumerator(objectsArray, OrderedDictionaryEnumerator.DictionaryEntry);
414+
EnsureObjectsArray();
415+
return new OrderedDictionaryEnumerator(_objectsArray, OrderedDictionaryEnumerator.DictionaryEntry);
377416
}
378417
#endregion
379418

380-
#region ISerializable implementation
419+
#region ISerializable implementation
381420
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
382421
{
383422
if (info == null)
@@ -390,6 +429,7 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte
390429
info.AddValue(InitCapacityName, _initialCapacity);
391430

392431
object[] serArray = new object[Count];
432+
EnsureObjectsArray();
393433
_objectsArray.CopyTo(serArray);
394434
info.AddValue(ArrayListName, serArray);
395435
}
@@ -399,7 +439,7 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte
399439
void IDeserializationCallback.OnDeserialization(object sender) {
400440
OnDeserialization(sender);
401441
}
402-
442+
403443
protected virtual void OnDeserialization(object sender)
404444
{
405445
if (_siInfo == null)
@@ -414,6 +454,8 @@ protected virtual void OnDeserialization(object sender)
414454

415455
if (serArray != null)
416456
{
457+
EnsureObjectsTable();
458+
EnsureObjectsArray();
417459
foreach (object o in serArray)
418460
{
419461
DictionaryEntry entry;
@@ -426,8 +468,8 @@ protected virtual void OnDeserialization(object sender)
426468
{
427469
throw new SerializationException(SR.OrderedDictionary_SerializationMismatch);
428470
}
429-
objectsArray.Add(entry);
430-
objectsTable.Add(entry.Key, entry.Value);
471+
_objectsArray.Add(entry);
472+
_objectsTable.Add(entry.Key, entry.Value);
431473
}
432474
}
433475
}

0 commit comments

Comments
 (0)