Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: third_party/protobuf/csharp/src/Google.Protobuf/Collections/MapField.cs

Issue 1322483002: Revert https://codereview.chromium.org/1291903002 (protobuf roll). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
33 using Google.Protobuf.Reflection;
34 using System;
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Linq;
38 using Google.Protobuf.Compatibility;
39
40 namespace Google.Protobuf.Collections
41 {
42 /// <summary>
43 /// Representation of a map field in a Protocol Buffer message.
44 /// </summary>
45 /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
46 /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
47 /// <remarks>
48 /// This implementation preserves insertion order for simplicity of testing
49 /// code using maps fields. Overwriting an existing entry does not change th e
50 /// position of that entry within the map. Equality is not order-sensitive.
51 /// For string keys, the equality comparison is provided by <see cref="Strin gComparer.Ordinal" />.
52 /// </remarks>
53 public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, T Value>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDiction ary
54 {
55 // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
56 private readonly bool allowNullValues;
57 private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TVal ue>>> map =
58 new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
59 private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new Linke dList<KeyValuePair<TKey, TValue>>();
60
61 /// <summary>
62 /// Constructs a new map field, defaulting the value nullability to only allow null values for message types
63 /// and non-nullable value types.
64 /// </summary>
65 public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue )) || Nullable.GetUnderlyingType(typeof(TValue)) != null)
66 {
67 }
68
69 /// <summary>
70 /// Constructs a new map field, overriding the choice of whether null va lues are permitted in the map.
71 /// This is used by wrapper types, where maps with string and bytes wrap pers as the value types
72 /// support null values.
73 /// </summary>
74 /// <param name="allowNullValues">Whether null values are permitted in t he map or not.</param>
75 public MapField(bool allowNullValues)
76 {
77 if (allowNullValues && typeof(TValue).IsValueType() && Nullable.GetU nderlyingType(typeof(TValue)) == null)
78 {
79 throw new ArgumentException("allowNullValues", "Non-nullable val ue types do not support null values");
80 }
81 this.allowNullValues = allowNullValues;
82 }
83
84 /// <summary>
85 /// Creates a deep clone of this object.
86 /// </summary>
87 /// <returns>
88 /// A deep clone of this object.
89 /// </returns>
90 public MapField<TKey, TValue> Clone()
91 {
92 var clone = new MapField<TKey, TValue>(allowNullValues);
93 // Keys are never cloneable. Values might be.
94 if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
95 {
96 foreach (var pair in list)
97 {
98 clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDee pCloneable<TValue>)pair.Value).Clone());
99 }
100 }
101 else
102 {
103 // Nothing is cloneable, so we don't need to worry.
104 clone.Add(this);
105 }
106 return clone;
107 }
108
109 /// <summary>
110 /// Adds the specified key/value pair to the map.
111 /// </summary>
112 /// <remarks>
113 /// This operation fails if the key already exists in the map. To replac e an existing entry, use the indexer.
114 /// </remarks>
115 /// <param name="key">The key to add</param>
116 /// <param name="value">The value to add.</param>
117 /// <exception cref="System.ArgumentException">The given key already exi sts in map.</exception>
118 public void Add(TKey key, TValue value)
119 {
120 // Validation of arguments happens in ContainsKey and the indexer
121 if (ContainsKey(key))
122 {
123 throw new ArgumentException("Key already exists in map", "key");
124 }
125 this[key] = value;
126 }
127
128 /// <summary>
129 /// Determines whether the specified key is present in the map.
130 /// </summary>
131 /// <param name="key">The key to check.</param>
132 /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
133 public bool ContainsKey(TKey key)
134 {
135 Preconditions.CheckNotNullUnconstrained(key, "key");
136 return map.ContainsKey(key);
137 }
138
139 private bool ContainsValue(TValue value)
140 {
141 var comparer = EqualityComparer<TValue>.Default;
142 return list.Any(pair => comparer.Equals(pair.Value, value));
143 }
144
145 /// <summary>
146 /// Removes the entry identified by the given key from the map.
147 /// </summary>
148 /// <param name="key">The key indicating the entry to remove from the ma p.</param>
149 /// <returns><c>true</c> if the map contained the given key before the e ntry was removed; <c>false</c> otherwise.</returns>
150 public bool Remove(TKey key)
151 {
152 Preconditions.CheckNotNullUnconstrained(key, "key");
153 LinkedListNode<KeyValuePair<TKey, TValue>> node;
154 if (map.TryGetValue(key, out node))
155 {
156 map.Remove(key);
157 node.List.Remove(node);
158 return true;
159 }
160 else
161 {
162 return false;
163 }
164 }
165
166 /// <summary>
167 /// Gets the value associated with the specified key.
168 /// </summary>
169 /// <param name="key">The key whose value to get.</param>
170 /// <param name="value">When this method returns, the value associated w ith the specified key, if the key is found;
171 /// otherwise, the default value for the type of the <paramref name="val ue"/> parameter.
172 /// This parameter is passed uninitialized.</param>
173 /// <returns><c>true</c> if the map contains an element with the specifi ed key; otherwise, <c>false</c>.</returns>
174 public bool TryGetValue(TKey key, out TValue value)
175 {
176 LinkedListNode<KeyValuePair<TKey, TValue>> node;
177 if (map.TryGetValue(key, out node))
178 {
179 value = node.Value.Value;
180 return true;
181 }
182 else
183 {
184 value = default(TValue);
185 return false;
186 }
187 }
188
189 /// <summary>
190 /// Gets or sets the value associated with the specified key.
191 /// </summary>
192 /// <param name="key">The key of the value to get or set.</param>
193 /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
194 /// <returns>The value associated with the specified key. If the specifi ed key is not found,
195 /// a get operation throws a <see cref="KeyNotFoundException"/>, and a s et operation creates a new element with the specified key.</returns>
196 public TValue this[TKey key]
197 {
198 get
199 {
200 Preconditions.CheckNotNullUnconstrained(key, "key");
201 TValue value;
202 if (TryGetValue(key, out value))
203 {
204 return value;
205 }
206 throw new KeyNotFoundException();
207 }
208 set
209 {
210 Preconditions.CheckNotNullUnconstrained(key, "key");
211 // value == null check here is redundant, but avoids boxing.
212 if (value == null && !allowNullValues)
213 {
214 Preconditions.CheckNotNullUnconstrained(value, "value");
215 }
216 LinkedListNode<KeyValuePair<TKey, TValue>> node;
217 var pair = new KeyValuePair<TKey, TValue>(key, value);
218 if (map.TryGetValue(key, out node))
219 {
220 node.Value = pair;
221 }
222 else
223 {
224 node = list.AddLast(pair);
225 map[key] = node;
226 }
227 }
228 }
229
230 /// <summary>
231 /// Gets a collection containing the keys in the map.
232 /// </summary>
233 public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pai r => pair.Key, ContainsKey); } }
234
235 /// <summary>
236 /// Gets a collection containing the values in the map.
237 /// </summary>
238 public ICollection<TValue> Values { get { return new MapView<TValue>(thi s, pair => pair.Value, ContainsValue); } }
239
240 /// <summary>
241 /// Adds the specified entries to the map.
242 /// </summary>
243 /// <param name="entries">The entries to add to the map.</param>
244 public void Add(IDictionary<TKey, TValue> entries)
245 {
246 Preconditions.CheckNotNull(entries, "entries");
247 foreach (var pair in entries)
248 {
249 Add(pair.Key, pair.Value);
250 }
251 }
252
253 /// <summary>
254 /// Returns an enumerator that iterates through the collection.
255 /// </summary>
256 /// <returns>
257 /// An enumerator that can be used to iterate through the collection.
258 /// </returns>
259 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
260 {
261 return list.GetEnumerator();
262 }
263
264 /// <summary>
265 /// Returns an enumerator that iterates through a collection.
266 /// </summary>
267 /// <returns>
268 /// An <see cref="T:System.Collections.IEnumerator" /> object that can b e used to iterate through the collection.
269 /// </returns>
270 IEnumerator IEnumerable.GetEnumerator()
271 {
272 return GetEnumerator();
273 }
274
275 /// <summary>
276 /// Adds the specified item to the map.
277 /// </summary>
278 /// <param name="item">The item to add to the map.</param>
279 void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TVal ue> item)
280 {
281 Add(item.Key, item.Value);
282 }
283
284 /// <summary>
285 /// Removes all items from the map.
286 /// </summary>
287 public void Clear()
288 {
289 list.Clear();
290 map.Clear();
291 }
292
293 /// <summary>
294 /// Determines whether map contains an entry equivalent to the given key /value pair.
295 /// </summary>
296 /// <param name="item">The key/value pair to find.</param>
297 /// <returns></returns>
298 bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
299 {
300 TValue value;
301 return TryGetValue(item.Key, out value)
302 && EqualityComparer<TValue>.Default.Equals(item.Value, value);
303 }
304
305 /// <summary>
306 /// Copies the key/value pairs in this map to an array.
307 /// </summary>
308 /// <param name="array">The array to copy the entries into.</param>
309 /// <param name="arrayIndex">The index of the array at which to start co pying values.</param>
310 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, T Value>[] array, int arrayIndex)
311 {
312 list.CopyTo(array, arrayIndex);
313 }
314
315 /// <summary>
316 /// Removes the specified key/value pair from the map.
317 /// </summary>
318 /// <remarks>Both the key and the value must be found for the entry to b e removed.</remarks>
319 /// <param name="item">The key/value pair to remove.</param>
320 /// <returns><c>true</c> if the key/value pair was found and removed; <c >false</c> otherwise.</returns>
321 bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, T Value> item)
322 {
323 if (item.Key == null)
324 {
325 throw new ArgumentException("Key is null", "item");
326 }
327 LinkedListNode<KeyValuePair<TKey, TValue>> node;
328 if (map.TryGetValue(item.Key, out node) &&
329 EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.V alue))
330 {
331 map.Remove(item.Key);
332 node.List.Remove(node);
333 return true;
334 }
335 else
336 {
337 return false;
338 }
339 }
340
341 /// <summary>
342 /// Returns whether or not this map allows values to be null.
343 /// </summary>
344 public bool AllowsNullValues { get { return allowNullValues; } }
345
346 /// <summary>
347 /// Gets the number of elements contained in the map.
348 /// </summary>
349 public int Count { get { return list.Count; } }
350
351 /// <summary>
352 /// Gets a value indicating whether the map is read-only.
353 /// </summary>
354 public bool IsReadOnly { get { return false; } }
355
356 /// <summary>
357 /// Determines whether the specified <see cref="System.Object" />, is eq ual to this instance.
358 /// </summary>
359 /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
360 /// <returns>
361 /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
362 /// </returns>
363 public override bool Equals(object other)
364 {
365 return Equals(other as MapField<TKey, TValue>);
366 }
367
368 /// <summary>
369 /// Returns a hash code for this instance.
370 /// </summary>
371 /// <returns>
372 /// A hash code for this instance, suitable for use in hashing algorithm s and data structures like a hash table.
373 /// </returns>
374 public override int GetHashCode()
375 {
376 var valueComparer = EqualityComparer<TValue>.Default;
377 int hash = 0;
378 foreach (var pair in list)
379 {
380 hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode( pair.Value);
381 }
382 return hash;
383 }
384
385 /// <summary>
386 /// Compares this map with another for equality.
387 /// </summary>
388 /// <remarks>
389 /// The order of the key/value pairs in the maps is not deemed significa nt in this comparison.
390 /// </remarks>
391 /// <param name="other">The map to compare this with.</param>
392 /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
393 public bool Equals(MapField<TKey, TValue> other)
394 {
395 if (other == null)
396 {
397 return false;
398 }
399 if (other == this)
400 {
401 return true;
402 }
403 if (other.Count != this.Count)
404 {
405 return false;
406 }
407 var valueComparer = EqualityComparer<TValue>.Default;
408 foreach (var pair in this)
409 {
410 TValue value;
411 if (!other.TryGetValue(pair.Key, out value))
412 {
413 return false;
414 }
415 if (!valueComparer.Equals(value, pair.Value))
416 {
417 return false;
418 }
419 }
420 return true;
421 }
422
423 /// <summary>
424 /// Adds entries to the map from the given stream.
425 /// </summary>
426 /// <remarks>
427 /// It is assumed that the stream is initially positioned after the tag specified by the codec.
428 /// This method will continue reading entries from the stream until the end is reached, or
429 /// a different tag is encountered.
430 /// </remarks>
431 /// <param name="input">Stream to read from</param>
432 /// <param name="codec">Codec describing how the key/value pairs are enc oded</param>
433 public void AddEntriesFrom(CodedInputStream input, Codec codec)
434 {
435 var adapter = new Codec.MessageAdapter(codec);
436 do
437 {
438 adapter.Reset();
439 input.ReadMessage(adapter);
440 this[adapter.Key] = adapter.Value;
441 } while (input.MaybeConsumeTag(codec.MapTag));
442 }
443
444 /// <summary>
445 /// Writes the contents of this map to the given coded output stream, us ing the specified codec
446 /// to encode each entry.
447 /// </summary>
448 /// <param name="output">The output stream to write to.</param>
449 /// <param name="codec">The codec to use for each entry.</param>
450 public void WriteTo(CodedOutputStream output, Codec codec)
451 {
452 var message = new Codec.MessageAdapter(codec);
453 foreach (var entry in list)
454 {
455 message.Key = entry.Key;
456 message.Value = entry.Value;
457 output.WriteTag(codec.MapTag);
458 output.WriteMessage(message);
459 }
460 }
461
462 /// <summary>
463 /// Calculates the size of this map based on the given entry codec.
464 /// </summary>
465 /// <param name="codec">The codec to use to encode each entry.</param>
466 /// <returns></returns>
467 public int CalculateSize(Codec codec)
468 {
469 if (Count == 0)
470 {
471 return 0;
472 }
473 var message = new Codec.MessageAdapter(codec);
474 int size = 0;
475 foreach (var entry in list)
476 {
477 message.Key = entry.Key;
478 message.Value = entry.Value;
479 size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
480 size += CodedOutputStream.ComputeMessageSize(message);
481 }
482 return size;
483 }
484
485 #region IDictionary explicit interface implementation
486 void IDictionary.Add(object key, object value)
487 {
488 Add((TKey)key, (TValue)value);
489 }
490
491 bool IDictionary.Contains(object key)
492 {
493 if (!(key is TKey))
494 {
495 return false;
496 }
497 return ContainsKey((TKey)key);
498 }
499
500 IDictionaryEnumerator IDictionary.GetEnumerator()
501 {
502 return new DictionaryEnumerator(GetEnumerator());
503 }
504
505 void IDictionary.Remove(object key)
506 {
507 Preconditions.CheckNotNull(key, "key");
508 if (!(key is TKey))
509 {
510 return;
511 }
512 Remove((TKey)key);
513 }
514
515 void ICollection.CopyTo(Array array, int index)
516 {
517 // This is ugly and slow as heck, but with any luck it will never be used anyway.
518 ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
519 temp.CopyTo(array, index);
520 }
521
522 bool IDictionary.IsFixedSize { get { return false; } }
523
524 ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
525
526 ICollection IDictionary.Values { get { return (ICollection)Values; } }
527
528 bool ICollection.IsSynchronized { get { return false; } }
529
530 object ICollection.SyncRoot { get { return this; } }
531
532 object IDictionary.this[object key]
533 {
534 get
535 {
536 Preconditions.CheckNotNull(key, "key");
537 if (!(key is TKey))
538 {
539 return null;
540 }
541 TValue value;
542 TryGetValue((TKey)key, out value);
543 return value;
544 }
545
546 set
547 {
548 this[(TKey)key] = (TValue)value;
549 }
550 }
551 #endregion
552
553 private class DictionaryEnumerator : IDictionaryEnumerator
554 {
555 private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
556
557 internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue> > enumerator)
558 {
559 this.enumerator = enumerator;
560 }
561
562 public bool MoveNext()
563 {
564 return enumerator.MoveNext();
565 }
566
567 public void Reset()
568 {
569 enumerator.Reset();
570 }
571
572 public object Current { get { return Entry; } }
573 public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
574 public object Key { get { return enumerator.Current.Key; } }
575 public object Value { get { return enumerator.Current.Value; } }
576 }
577
578 /// <summary>
579 /// A codec for a specific map field. This contains all the information required to encode and
580 /// decode the nested messages.
581 /// </summary>
582 public sealed class Codec
583 {
584 private readonly FieldCodec<TKey> keyCodec;
585 private readonly FieldCodec<TValue> valueCodec;
586 private readonly uint mapTag;
587
588 /// <summary>
589 /// Creates a new entry codec based on a separate key codec and valu e codec,
590 /// and the tag to use for each map entry.
591 /// </summary>
592 /// <param name="keyCodec">The key codec.</param>
593 /// <param name="valueCodec">The value codec.</param>
594 /// <param name="mapTag">The map tag to use to introduce each map en try.</param>
595 public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCode c, uint mapTag)
596 {
597 this.keyCodec = keyCodec;
598 this.valueCodec = valueCodec;
599 this.mapTag = mapTag;
600 }
601
602 /// <summary>
603 /// The tag used in the enclosing message to indicate map entries.
604 /// </summary>
605 internal uint MapTag { get { return mapTag; } }
606
607 /// <summary>
608 /// A mutable message class, used for parsing and serializing. This
609 /// delegates the work to a codec, but implements the <see cref="IMe ssage"/> interface
610 /// for interop with <see cref="CodedInputStream"/> and <see cref="C odedOutputStream"/>.
611 /// This is nested inside Codec as it's tightly coupled to the assoc iated codec,
612 /// and it's simpler if it has direct access to all its fields.
613 /// </summary>
614 internal class MessageAdapter : IMessage
615 {
616 private readonly Codec codec;
617 internal TKey Key { get; set; }
618 internal TValue Value { get; set; }
619
620 internal MessageAdapter(Codec codec)
621 {
622 this.codec = codec;
623 }
624
625 internal void Reset()
626 {
627 Key = codec.keyCodec.DefaultValue;
628 Value = codec.valueCodec.DefaultValue;
629 }
630
631 public void MergeFrom(CodedInputStream input)
632 {
633 uint tag;
634 while ((tag = input.ReadTag()) != 0)
635 {
636 if (tag == codec.keyCodec.Tag)
637 {
638 Key = codec.keyCodec.Read(input);
639 }
640 else if (tag == codec.valueCodec.Tag)
641 {
642 Value = codec.valueCodec.Read(input);
643 }
644 else
645 {
646 input.SkipLastField();
647 }
648 }
649 }
650
651 public void WriteTo(CodedOutputStream output)
652 {
653 codec.keyCodec.WriteTagAndValue(output, Key);
654 codec.valueCodec.WriteTagAndValue(output, Value);
655 }
656
657 public int CalculateSize()
658 {
659 return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valu eCodec.CalculateSizeWithTag(Value);
660 }
661
662 MessageDescriptor IMessage.Descriptor { get { return null; } }
663 }
664 }
665
666 private class MapView<T> : ICollection<T>, ICollection
667 {
668 private readonly MapField<TKey, TValue> parent;
669 private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
670 private readonly Func<T, bool> containsCheck;
671
672 internal MapView(
673 MapField<TKey, TValue> parent,
674 Func<KeyValuePair<TKey, TValue>, T> projection,
675 Func<T, bool> containsCheck)
676 {
677 this.parent = parent;
678 this.projection = projection;
679 this.containsCheck = containsCheck;
680 }
681
682 public int Count { get { return parent.Count; } }
683
684 public bool IsReadOnly { get { return true; } }
685
686 public bool IsSynchronized { get { return false; } }
687
688 public object SyncRoot { get { return parent; } }
689
690 public void Add(T item)
691 {
692 throw new NotSupportedException();
693 }
694
695 public void Clear()
696 {
697 throw new NotSupportedException();
698 }
699
700 public bool Contains(T item)
701 {
702 return containsCheck(item);
703 }
704
705 public void CopyTo(T[] array, int arrayIndex)
706 {
707 if (arrayIndex < 0)
708 {
709 throw new ArgumentOutOfRangeException("arrayIndex");
710 }
711 if (arrayIndex + Count >= array.Length)
712 {
713 throw new ArgumentException("Not enough space in the array", "array");
714 }
715 foreach (var item in this)
716 {
717 array[arrayIndex++] = item;
718 }
719 }
720
721 public IEnumerator<T> GetEnumerator()
722 {
723 return parent.list.Select(projection).GetEnumerator();
724 }
725
726 public bool Remove(T item)
727 {
728 throw new NotSupportedException();
729 }
730
731 IEnumerator IEnumerable.GetEnumerator()
732 {
733 return GetEnumerator();
734 }
735
736 public void CopyTo(Array array, int index)
737 {
738 if (index < 0)
739 {
740 throw new ArgumentOutOfRangeException("index");
741 }
742 if (index + Count >= array.Length)
743 {
744 throw new ArgumentException("Not enough space in the array", "array");
745 }
746 foreach (var item in this)
747 {
748 array.SetValue(item, index++);
749 }
750 }
751 }
752 }
753 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698