Sunday, November 25, 2007

JScript Arrays

Have you ever tried to use a .NET array in JScript? For example, suppose you have a class library with a method that returns an array of a custom type (MyObject[]). You would think you could enumerate the members using the syntax

    for (var x in GetMyObjects())

After all, an array implements IEnumerable. Well, it does, but it does it wrong, at least in JScript. The values of x will be the indices of the array. Yeah, that's right: 1, 2, 3...

The for-in construct in JScript is not quite the same as foreach in C#. It has to accomodate expando properties as well. Somehow it gets confused with .NET arrays.

Here's a workaround. Wrap your array in an IEnumerable. In C#:

    using System;
    using System.Collections.Generic;
    using System.Collections;

    public class ProtectedArray<T> : IEnumerable<T>, IEnumerable
    {
        private T[] _innerArray;

        public ProtectedArray(T[] innerArray)
        {
            _innerArray = innerArray;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return ((IEnumerable)_innerArray).GetEnumerator();
        }

        public Int32 Length
        {
            get    {return _innerArray.Length;}
        }

        public T this[Int32 index]
        {
            get {return _innerArray[index];}
            set    {_innerArray[index] = value;}
        }

        public T[] ToArray()
        {
            return _innerArray;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)this.GetEnumerator();
        }
    }

(My apologies if <T> disappeared anywhere in there. The editor thinks it is an unknown HTML tag. I tried to find them all.)

Now, if GetMyObjects() returns a ProtectedArray, you can enumerate in JScript using the above syntax. You can also try the following if you don't want to change your API, but you may need to modify the ProtectedArray class because JScript cannot handle the generic declaration.

    for (var x in new ProtectedArray(GetMyObjects()))

No comments: