00e0430d3de27dc3b5019a4a2cb84604d1934cc4
[mono.git] / mcs / class / corlib / System / Array.cs
1 //
2 // System.Array.cs
3 //
4 // Authors:
5 //   Joe Shaw (joe@ximian.com)
6 //   Martin Baulig (martin@gnome.org)
7 //   Dietmar Maurer (dietmar@ximian.com)
8 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 //   Jeffrey Stedfast (fejj@novell.com)
10 //   Marek Safar (marek.safar@gmail.com)
11 //
12 // (C) 2001-2003 Ximian, Inc.  http://www.ximian.com
13 // Copyright (C) 2004-2011 Novell, Inc (http://www.novell.com)
14 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39
40 using System.Collections.Generic;
41 using System.Collections.ObjectModel;
42 using System.Runtime.ConstrainedExecution;
43
44 namespace System
45 {
46         public abstract partial class Array
47         {
48                 // Constructor
49                 private Array ()
50                 {
51                 }
52
53                 /*
54                  * These methods are used to implement the implicit generic interfaces 
55                  * implemented by arrays in NET 2.0.
56                  * Only make those methods generic which really need it, to avoid
57                  * creating useless instantiations.
58                  */
59                 internal int InternalArray__ICollection_get_Count ()
60                 {
61                         return Length;
62                 }
63
64                 internal bool InternalArray__ICollection_get_IsReadOnly ()
65                 {
66                         return true;
67                 }
68
69                 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
70                 {
71                         return new InternalEnumerator<T> (this);
72                 }
73
74                 internal void InternalArray__ICollection_Clear ()
75                 {
76                         throw new NotSupportedException ("Collection is read-only");
77                 }
78
79                 internal void InternalArray__ICollection_Add<T> (T item)
80                 {
81                         throw new NotSupportedException ("Collection is of a fixed size");
82                 }
83
84                 internal bool InternalArray__ICollection_Remove<T> (T item)
85                 {
86                         throw new NotSupportedException ("Collection is of a fixed size");
87                 }
88
89                 internal bool InternalArray__ICollection_Contains<T> (T item)
90                 {
91                         if (this.Rank > 1)
92                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
93
94                         int length = this.Length;
95                         for (int i = 0; i < length; i++) {
96                                 T value;
97                                 GetGenericValueImpl (i, out value);
98                                 if (item == null){
99                                         if (value == null) {
100                                                 return true;
101                                         }
102
103                                         continue;
104                                 }
105
106                                 if (item.Equals (value)) {
107                                         return true;
108                                 }
109                         }
110
111                         return false;
112                 }
113
114                 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int arrayIndex)
115                 {
116                         Copy (this, GetLowerBound (0), array, arrayIndex, Length);
117                 }
118
119                 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
120                 {
121                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
122                                 throw new ArgumentOutOfRangeException ("index");
123
124                         T value;
125                         GetGenericValueImpl (index, out value);
126                         return value;
127                 }
128
129                 internal int InternalArray__IReadOnlyCollection_get_Count ()
130                 {
131                         return Length;
132                 }
133
134                 internal void InternalArray__Insert<T> (int index, T item)
135                 {
136                         throw new NotSupportedException ("Collection is of a fixed size");
137                 }
138
139                 internal void InternalArray__RemoveAt (int index)
140                 {
141                         throw new NotSupportedException ("Collection is of a fixed size");
142                 }
143
144                 internal int InternalArray__IndexOf<T> (T item)
145                 {
146                         if (this.Rank > 1)
147                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
148
149                         int length = this.Length;
150                         for (int i = 0; i < length; i++) {
151                                 T value;
152                                 GetGenericValueImpl (i, out value);
153                                 if (item == null){
154                                         if (value == null)
155                                                 return i + this.GetLowerBound (0);
156
157                                         continue;
158                                 }
159                                 if (value.Equals (item))
160                                         // array index may not be zero-based.
161                                         // use lower bound
162                                         return i + this.GetLowerBound (0);
163                         }
164
165                         unchecked {
166                                 // lower bound may be MinValue
167                                 return this.GetLowerBound (0) - 1;
168                         }
169                 }
170
171                 internal T InternalArray__get_Item<T> (int index)
172                 {
173                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
174                                 throw new ArgumentOutOfRangeException ("index");
175
176                         T value;
177                         GetGenericValueImpl (index, out value);
178                         return value;
179                 }
180
181                 internal void InternalArray__set_Item<T> (int index, T item)
182                 {
183                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
184                                 throw new ArgumentOutOfRangeException ("index");
185
186                         object[] oarray = this as object [];
187                         if (oarray != null) {
188                                 oarray [index] = (object)item;
189                                 return;
190                         }
191                         SetGenericValueImpl (index, ref item);
192                 }
193
194                 // CAUTION! No bounds checking!
195                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
196                 internal extern void GetGenericValueImpl<T> (int pos, out T value);
197
198                 // CAUTION! No bounds checking!
199                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
200                 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
201
202                 internal struct InternalEnumerator<T> : IEnumerator<T>
203                 {
204                         const int NOT_STARTED = -2;
205                         
206                         // this MUST be -1, because we depend on it in move next.
207                         // we just decr the size, so, 0 - 1 == FINISHED
208                         const int FINISHED = -1;
209                         
210                         Array array;
211                         int idx;
212
213                         internal InternalEnumerator (Array array)
214                         {
215                                 this.array = array;
216                                 idx = NOT_STARTED;
217                         }
218
219                         public void Dispose ()
220                         {
221                                 idx = NOT_STARTED;
222                         }
223
224                         public bool MoveNext ()
225                         {
226                                 if (idx == NOT_STARTED)
227                                         idx = array.Length;
228
229                                 return idx != FINISHED && -- idx != FINISHED;
230                         }
231
232                         public T Current {
233                                 get {
234                                         if (idx == NOT_STARTED)
235                                                 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
236                                         if (idx == FINISHED)
237                                                 throw new InvalidOperationException ("Enumeration already finished");
238
239                                         return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
240                                 }
241                         }
242
243                         void IEnumerator.Reset ()
244                         {
245                                 idx = NOT_STARTED;
246                         }
247
248                         object IEnumerator.Current {
249                                 get {
250                                         return Current;
251                                 }
252                         }
253                 }
254
255                 // Properties
256                 public int Length {
257                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
258                         get {
259                                 int length = this.GetLength (0);
260
261                                 for (int i = 1; i < this.Rank; i++) {
262                                         length *= this.GetLength (i); 
263                                 }
264                                 return length;
265                         }
266                 }
267
268                 public int Rank {
269                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
270                         get {
271                                 return this.GetRank ();
272                         }
273                 }
274
275                 // InternalCall Methods
276                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
277                 extern int GetRank ();
278
279                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
280                 public extern int GetLength (int dimension);
281
282                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
283                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
284                 public extern int GetLowerBound (int dimension);
285
286                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
287                 public extern object GetValue (params int[] indices);
288
289                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
290                 public extern void SetValue (object value, params int[] indices);
291
292                 // CAUTION! No bounds checking!
293                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
294                 internal extern object GetValueImpl (int pos);
295
296                 // CAUTION! No bounds checking!
297                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
298                 internal extern void SetValueImpl (object value, int pos);
299
300                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
301                 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
302
303                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
304                 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
305
306                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
307                 public int GetUpperBound (int dimension)
308                 {
309                         return GetLowerBound (dimension) + GetLength (dimension) - 1;
310                 }
311
312                 public object GetValue (int index)
313                 {
314                         if (Rank != 1)
315                                 throw new ArgumentException (SR.Arg_RankMultiDimNotSupported);
316
317                         var lb  = GetLowerBound (0);
318                         if (index < lb || index > GetUpperBound (0))
319                                 throw new IndexOutOfRangeException (Locale.GetText (
320                                         "Index has to be between upper and lower bound of the array."));
321
322                         if (GetType ().GetElementType ().IsPointer)
323                                 throw new NotSupportedException ("Type is not supported");
324
325                         return GetValueImpl (index - lb);
326                 }
327
328                 public object GetValue (int index1, int index2)
329                 {
330                         int[] ind = {index1, index2};
331                         return GetValue (ind);
332                 }
333
334                 public object GetValue (int index1, int index2, int index3)
335                 {
336                         int[] ind = {index1, index2, index3};
337                         return GetValue (ind);
338                 }
339
340                 public void SetValue (object value, int index)
341                 {
342                         if (Rank != 1)
343                                 throw new ArgumentException (SR.Arg_RankMultiDimNotSupported);
344
345                         var lb  = GetLowerBound (0);
346                         if (index < lb || index > GetUpperBound (0))
347                                 throw new IndexOutOfRangeException (Locale.GetText (
348                                         "Index has to be >= lower bound and <= upper bound of the array."));
349
350                         if (GetType ().GetElementType ().IsPointer)
351                                 throw new NotSupportedException ("Type is not supported");
352
353                         SetValueImpl (value, index - lb);
354                 }
355
356                 public void SetValue (object value, int index1, int index2)
357                 {
358                         int[] ind = {index1, index2};
359                         SetValue (value, ind);
360                 }
361
362                 public void SetValue (object value, int index1, int index2, int index3)
363                 {
364                         int[] ind = {index1, index2, index3};
365                         SetValue (value, ind);
366                 }
367
368                 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
369                 {
370                         return CreateInstance(elementType, lengths, lowerBounds);
371                 }
372
373                 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
374                 {
375                         return CreateInstance (elementType, length1, length2);
376                 }
377
378                 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
379                 {
380                         return CreateInstance(elementType, lengths);
381                 }
382
383                 public static Array CreateInstance (Type elementType, int length)
384                 {
385                         int[] lengths = {length};
386
387                         return CreateInstance (elementType, lengths);
388                 }
389
390                 public static Array CreateInstance (Type elementType, int length1, int length2)
391                 {
392                         int[] lengths = {length1, length2};
393
394                         return CreateInstance (elementType, lengths);
395                 }
396
397                 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
398                 {
399                         int[] lengths = {length1, length2, length3};
400
401                         return CreateInstance (elementType, lengths);
402                 }
403
404                 public static Array CreateInstance (Type elementType, params int[] lengths)
405                 {
406                         if (elementType == null)
407                                 throw new ArgumentNullException ("elementType");
408                         if (lengths == null)
409                                 throw new ArgumentNullException ("lengths");
410
411                         if (lengths.Length > 255)
412                                 throw new TypeLoadException ();
413
414                         int[] bounds = null;
415
416                         elementType = elementType.UnderlyingSystemType as RuntimeType;
417                         if (elementType == null)
418                                 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
419                         if (elementType.Equals (typeof (void)))
420                                 throw new NotSupportedException ("Array type can not be void");
421                         if (elementType.ContainsGenericParameters)
422                                 throw new NotSupportedException ("Array type can not be an open generic type");
423                         
424                         return CreateInstanceImpl (elementType, lengths, bounds);
425                 }
426
427                 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
428                 {
429                         if (elementType == null)
430                                 throw new ArgumentNullException ("elementType");
431                         if (lengths == null)
432                                 throw new ArgumentNullException ("lengths");
433                         if (lowerBounds == null)
434                                 throw new ArgumentNullException ("lowerBounds");
435
436                         elementType = elementType.UnderlyingSystemType as RuntimeType;
437                         if (elementType == null)
438                                 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
439                         if (elementType.Equals (typeof (void)))
440                                 throw new NotSupportedException ("Array type can not be void");
441                         if (elementType.ContainsGenericParameters)
442                                 throw new NotSupportedException ("Array type can not be an open generic type");
443
444                         if (lengths.Length < 1)
445                                 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
446
447                         if (lengths.Length != lowerBounds.Length)
448                                 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
449
450                         for (int j = 0; j < lowerBounds.Length; j ++) {
451                                 if (lengths [j] < 0)
452                                         throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
453                                                 "Each value has to be >= 0."));
454                                 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
455                                         throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
456                                                 "Length + bound must not exceed Int32.MaxValue."));
457                         }
458
459                         if (lengths.Length > 255)
460                                 throw new TypeLoadException ();
461
462                         return CreateInstanceImpl (elementType, lengths, lowerBounds);
463                 }
464
465                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
466                 public static void Clear (Array array, int index, int length)
467                 {
468                         if (array == null)
469                                 throw new ArgumentNullException ("array");
470                         if (length < 0)
471                                 throw new IndexOutOfRangeException ("length < 0");
472
473                         int low = array.GetLowerBound (0);
474                         if (index < low)
475                                 throw new IndexOutOfRangeException ("index < lower bound");
476                         index = index - low;
477
478                         // re-ordered to avoid possible integer overflow
479                         if (index > array.Length - length)
480                                 throw new IndexOutOfRangeException ("index + length > size");
481
482                         ClearInternal (array, index, length);
483                 }
484                 
485                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
486                 static extern void ClearInternal (Array a, int index, int count);
487
488                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
489                 public static void Copy (Array sourceArray, Array destinationArray, int length)
490                 {
491                         // need these checks here because we are going to use
492                         // GetLowerBound() on source and dest.
493                         if (sourceArray == null)
494                                 throw new ArgumentNullException ("sourceArray");
495
496                         if (destinationArray == null)
497                                 throw new ArgumentNullException ("destinationArray");
498
499                         Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
500                                 destinationArray.GetLowerBound (0), length);
501                 }
502
503                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
504                 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
505                 {
506                         if (sourceArray == null)
507                                 throw new ArgumentNullException ("sourceArray");
508
509                         if (destinationArray == null)
510                                 throw new ArgumentNullException ("destinationArray");
511
512                         if (length < 0)
513                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
514                                         "Value has to be >= 0."));;
515
516                         if (sourceArray.Rank != destinationArray.Rank)
517                                 throw new RankException(SR.Rank_MultiDimNotSupported);
518
519                         if (sourceIndex < 0)
520                                 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
521                                         "Value has to be >= 0."));;
522
523                         if (destinationIndex < 0)
524                                 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
525                                         "Value has to be >= 0."));;
526
527                         if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
528                                 return;
529
530                         int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
531                         int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
532
533                         if (dest_pos < 0)
534                                 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
535
536                         // re-ordered to avoid possible integer overflow
537                         if (source_pos > sourceArray.Length - length)
538                                 throw new ArgumentException ("length");
539
540                         if (dest_pos > destinationArray.Length - length) {
541                                 string msg = "Destination array was not long enough. Check " +
542                                         "destIndex and length, and the array's lower bounds";
543                                 throw new ArgumentException (msg, string.Empty);
544                         }
545
546                         Type src_type = sourceArray.GetType ().GetElementType ();
547                         Type dst_type = destinationArray.GetType ().GetElementType ();
548
549                         if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
550                                 for (int i = 0; i < length; i++) {
551                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
552
553                                         try {
554                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
555                                         } catch (ArgumentException) {
556                                                 throw CreateArrayTypeMismatchException ();
557                                         } catch {
558                                                 if (CanAssignArrayElement (src_type, dst_type))
559                                                         throw;
560
561                                                 throw CreateArrayTypeMismatchException ();
562                                         }
563                                 }
564                         }
565                         else {
566                                 for (int i = length - 1; i >= 0; i--) {
567                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
568
569                                         try {
570                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
571                                         } catch (ArgumentException) {
572                                                 throw CreateArrayTypeMismatchException ();
573                                         } catch {
574                                                 if (CanAssignArrayElement (src_type, dst_type))
575                                                         throw;
576
577                                                 throw CreateArrayTypeMismatchException ();
578                                         }
579                                 }
580                         }
581                 }
582
583                 static Exception CreateArrayTypeMismatchException ()
584                 {
585                         return new ArrayTypeMismatchException ();
586                 }
587
588                 static bool CanAssignArrayElement (Type source, Type target)
589                 {
590                         if (source.IsValueType)
591                                 return source.IsAssignableFrom (target);
592
593                         if (source.IsInterface)
594                                 return !target.IsValueType;
595
596                         if (target.IsInterface)
597                                 return !source.IsValueType;
598
599                         return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
600                 }
601
602                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
603                 //
604                 // The constrained copy should guarantee that if there is an exception thrown
605                 // during the copy, the destination array remains unchanged.
606                 // This is related to System.Runtime.Reliability.CER
607                 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
608                 {
609                         Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
610                 }
611
612                 public static T[] Empty<T>()
613                 {
614                         return EmptyArray<T>.Value;
615                 }
616
617                 public void Initialize()
618                 {
619                         return;
620                 }
621
622                 static int IndexOfImpl<T>(T[] array, T value, int startIndex, int count)
623                 {
624                         return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, count);
625                 }
626
627                 static int LastIndexOfImpl<T>(T[] array, T value, int startIndex, int count)
628                 {
629                         return EqualityComparer<T>.Default.LastIndexOf (array, value, startIndex, count);
630                 }
631
632                 static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
633                 {
634                         Object[] objKeys = keys as Object[];
635                         Object[] objItems = null;
636                         if (objKeys != null)
637                                 objItems = items as Object[];
638
639                         if (objKeys != null && (items == null || objItems != null)) {
640                                 SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
641                                 sorter.Sort(index, length);
642                         } else {
643                                 SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
644                                 sorter.Sort(index, length);
645                         }
646                 }
647
648                 #region Unsafe array operations
649
650                 //
651                 // Loads array index with no safety checks (JIT intristics)
652                 //
653                 internal static T UnsafeLoad<T> (T[] array, int index) {
654                         return array [index];
655                 }
656
657                 //
658                 // Stores values at specified array index with no safety checks (JIT intristics)
659                 //
660                 internal static void UnsafeStore<T> (T[] array, int index, T value) {
661                         array [index] = value;
662                 }
663
664                 //
665                 // Moved value from instance into target of different type with no checks (JIT intristics)
666                 //
667                 // Restrictions:
668                 //
669                 // S and R must either:
670                 //       both be blitable valuetypes
671                 //       both be reference types (IOW, an unsafe cast)
672                 // S and R cannot be float or double
673                 // S and R must either:
674                 //       both be a struct
675                 //       both be a scalar
676                 // S and R must either:
677                 //       be of same size
678                 //       both be a scalar of size <= 4
679                 //
680                 internal static R UnsafeMov<S,R> (S instance) {
681                         return (R)(object) instance;
682                 }
683
684                 #endregion
685
686                 internal sealed class FunctorComparer<T> : IComparer<T> {
687                         Comparison<T> comparison;
688
689                         public FunctorComparer(Comparison<T> comparison) {
690                                 this.comparison = comparison;
691                         }
692
693                         public int Compare(T x, T y) {
694                                 return comparison(x, y);
695                         }
696                 }
697
698                 partial class ArrayEnumerator
699                 {
700                         public Object Current {
701                                 get {
702                                         if (_index < 0) throw new InvalidOperationException (SR.InvalidOperation_EnumNotStarted);
703                                         if (_index >= _endIndex) throw new InvalidOperationException (SR.InvalidOperation_EnumEnded);
704                                         if (_index == 0 && _array.GetType ().GetElementType ().IsPointer) throw new NotSupportedException ("Type is not supported");
705                                         return _array.GetValueImpl(_index);
706                                 }
707                         }
708                 }
709         }
710 }