Hashtable.CopyTo and CopyToCollection bug

Hi,

The Hashtable.CopyTo and CopyToCollection methods does not return the expected result. Here is the summary for ICollection.CopyTo:

        // Summary:
        //     Copies the elements of the System.Collections.ICollection to an System.Array,
        //     starting at a particular System.Array index.
        //
        // Parameters:
        //   array:
        //     The one-dimensional System.Array that is the destination of the elements copied
        //     from System.Collections.ICollection. The System.Array must have zero-based indexing.
        //
        //   index:
        //     The zero-based index in array at which copying begins.

This is also confirmed by the full .NET example found here: Hashtable.CopyTo(Array, Int32) Method

The problem is that the TinyCLR Hashtable implementation uses “index” as the starting index in the Hashtable. This does not make any sence since the entries in the Hashtable are indexed according to the Keys hash value.

Hashtable.CopyTo code:

        public void CopyTo(Array array, int index) {
            if (index < 0 && index > this._buckets.Length)
                throw new IndexOutOfRangeException("index");

            var j = 0;
            var len = array.Length;
            for (var i = index; i < this._buckets.Length; i++) {
                for (var cur = this._buckets[i]; cur != null && j < len; cur = cur.next) {
                    ((IList)array)[j] = new DictionaryEntry(cur.key, cur.value);
                    j++;
                }
            }
        }

Hashtable.CopyToCollection code:

        //implementation for KeyCollection and ValueCollection copyTo method
        private void CopyToCollection(Array array, int index, EnumeratorType type) {
            if (index < 0 && index > this._numberOfBuckets)
                throw new IndexOutOfRangeException("index");

            var j = 0;
            var len = array.Length;

            for (var i = index; i < this._numberOfBuckets; i++) {
                for (var cur = this._buckets[i]; cur != null && j < len; cur = cur.next) {
                    if (type == EnumeratorType.KEY)
                        ((IList)array)[j] = cur.key;
                    else
                        ((IList)array)[j] = cur.value;

                    j++;
                }
            }
        }

Also, the conditions for throwing the IndexOutOfRangeException looks to be wrong. I am guessing it should be “||”, not “&&”. But this is anyways incorrect since “index” should reference the destination “array”, not “this._buckets”…

Test code from Hashtable.CopyTo(Array, Int32) Method:

        public static void Test() {
            // Creates and initializes the source Hashtable.
            var mySourceHT = new Hashtable();
            mySourceHT.Add("A", "valueA");
            mySourceHT.Add("B", "valueB");

            // Creates and initializes the one-dimensional target Array.
            var myTargetArray = new string[15];
            myTargetArray[0] = "The";
            myTargetArray[1] = "quick";
            myTargetArray[2] = "brown";
            myTargetArray[3] = "fox";
            myTargetArray[4] = "jumps";
            myTargetArray[5] = "over";
            myTargetArray[6] = "the";
            myTargetArray[7] = "lazy";
            myTargetArray[8] = "dog";
            myTargetArray[9] = "";
            myTargetArray[10] = "";
            myTargetArray[11] = "";
            myTargetArray[12] = "";
            myTargetArray[13] = "";
            myTargetArray[14] = "";

            // Displays the values of the target Array.
            Debug.WriteLine("The target Array contains the following before:");
            PrintValues(myTargetArray, ' ');

            // Copies the keys in the source Hashtable to the target Hashtable, starting at index 6.
            Debug.WriteLine("After copying the keys, starting at index 6:");
            mySourceHT.Keys.CopyTo(myTargetArray, 6);

            // Displays the values of the target Array.
            PrintValues(myTargetArray, ' ');

            // Copies the values in the source Hashtable to the target Hashtable, starting at index 6.
            Debug.WriteLine("After copying the values, starting at index 6:");
            mySourceHT.Values.CopyTo(myTargetArray, 6);

            // Displays the values of the target Array.
            PrintValues(myTargetArray, ' ');
        }

        public static void PrintValues(string[] myArr, char mySeparator) {
            for (int i = 0; i < myArr.Length; i++)
                Debug.Write($"{mySeparator}{myArr[i]}");
            Debug.WriteLine("");
        }

The expected output is:

The target Array contains the following before:
 The quick brown fox jumps over the lazy dog
After copying the keys, starting at index 6:
 The quick brown fox jumps over B A dog
After copying the values, starting at index 6:
 The quick brown fox jumps over valueB valueA dog

The actual output is:

The target Array contains the following before:
 The quick brown fox jumps over the lazy dog      
After copying the keys, starting at index 6:
 The quick brown fox jumps over the lazy dog      
After copying the values, starting at index 6:
 The quick brown fox jumps over the lazy dog  

There is nothing at index 6 in the Hashtable, so nothing gets copied. Also the IndexOutOfRangeException does not get thrown.