private object HandleArrayBasedAssocArray(AssociativeArray array, Type arrayType)
        {
            object ret;
            Type elementType = arrayType.GetElementType();

            ConstructorInfo[] ctors = elementType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);

            ConstructorInfo[] matches = ctors.Where(ct => ct.GetParameters().Length == 2).ToArray();

            if (matches.Length == 1)
            {
                Array newArray = Array.CreateInstance(elementType, array.Elements.Length);
                Action<int, object, object> handleKeyValuePair =
                    (index, key, value) =>
                    {
                        object newValue = matches[0].Invoke(new[] { key, value });
                        newArray.SetValue(newValue, index);
                    };

                // this is slightly wasteful as we already asked for the parameters once, but it's a one-off operation.
                ParameterInfo[] parameters = matches[0].GetParameters();

                for (int elemNum = 0; elemNum < array.Elements.Length; elemNum++)
                {
                    this._targetType.Push(parameters[0].ParameterType);
                    KeyValuePair<AstNode, AstNode> element = array.Elements[elemNum];

                    object keyValue = element.Key.Visit(this);
                    this._targetType.Pop();

                    this._targetType.Push(parameters[1].ParameterType);

                    object valueValue = element.Value.Visit(this);
                    this._targetType.Pop();

                    handleKeyValuePair(elemNum, keyValue, valueValue);
                }

                // set return value
                ret = newArray;
            }
            else if (matches.Length == 0)
            {
                throw new NotSupportedException(
                    string.Format(Resources.Exceptions.UnsupportedAssocParameterArrayTypeNoConstructor,
                                  elementType.FullName));
            }
            else
            {
                throw new NotSupportedException(
                    string.Format(Resources.Exceptions.UnsupportedAssocParameterArrayTypeAmbiguousConstructor,
                                  elementType.FullName));
            }

            return ret;
        }
 private object HandleInterfaceBasedAssocArray(AssociativeArray array, Type targetType)
 {
     Type realType = this.OnResolveInterfaceType(targetType);
     return HandleMethodBasedAssocArray(array, realType);
 }
        protected virtual object Visit(AssociativeArray array)
        {
            object ret;
            Type targetType = this._targetType.Peek();
            if (targetType.IsInterface)
                ret = this.HandleInterfaceBasedAssocArray(array, targetType);
            else if (targetType.IsArray)
                ret = this.HandleArrayBasedAssocArray(array, targetType);
            else
                ret = this.HandleMethodBasedAssocArray(array, targetType);

            return ret;
        }
        private object HandleMethodBasedAssocArray(AssociativeArray array, Type targetType)
        {
            object ret;

            try
            {
                ret = Activator.CreateInstance(targetType);
            }
            catch (MissingMethodException)
            {
                throw new NotSupportedException(
                    string.Format(Resources.Exceptions.UnsupportedParameterTypeNoDefaultConstructor,
                                  targetType.FullName));
            }
            catch (MissingMemberException)
            {
                // portable class library
                throw new NotSupportedException(
                    string.Format(Resources.Exceptions.UnsupportedParameterTypeNoDefaultConstructor,
                                  targetType.FullName));
            }


            MethodInfo[] addMethods = targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                                                .Where(m => StringComparer.OrdinalIgnoreCase.Equals(m.Name, "Add"))
                                                .ToArray();

            var addWithTwoArgs = addMethods.Where(m => m.GetParameters().Length == 2).ToArray();
            var addWithOneArgs = addMethods.Where(m => m.GetParameters().Length == 1).ToArray();

            for (int elementNum = 0; elementNum < array.Elements.Length; elementNum++)
            {
                KeyValuePair<AstNode, AstNode> elem = array.Elements[elementNum];
                bool success = false;
                for (int addNum = 0; addNum < addWithTwoArgs.Length; addNum++)
                {
                    ParameterInfo[] addParameters = addWithTwoArgs[addNum].GetParameters();

                    var keyType = addParameters[0].ParameterType;
                    var keyNode = elem.Key;
                    this._targetType.Push(keyType);
                    var keyValue = keyNode.Visit(this);
                    this._targetType.Pop();
                    success = keyType.IsInstanceOfType(keyValue);

                    if (success)
                    {
                        var valueType = addParameters[1].ParameterType;
                        var valueNode = elem.Value;
                        this._targetType.Push(valueType);
                        var valueValue = valueNode.Visit(this);
                        this._targetType.Pop();

                        success = valueType.IsInstanceOfType(valueValue);

                        if (success)
                        {
                            try
                            {
                                addWithTwoArgs[addNum].Invoke(ret, new[] { keyValue, valueValue });
                                break;
                            }
                            catch (TargetInvocationException ex)
                            {
                                this.RaiseError(new AddError(addWithTwoArgs[addNum],
                                                             new[] {keyValue, valueValue},
                                                             new[] {keyNode, valueNode},
                                                             ex.InnerException));
                            }
                        }
                    }
                }

                if (!success)
                {
                    for (int addNum = 0; addNum < addWithOneArgs.Length; addNum++)
                    {
                        ParameterInfo[] addParameters = addWithOneArgs[addNum].GetParameters();

                        var addParam = addParameters[0];
                        var addParamtype = addParam.ParameterType;

                        var paramTypeCtors =
                            addParamtype.GetConstructors()
                                        .Where(ct => ct.GetParameters().Length == 2)
                                        .ToArray();

                        for (int ctorNum = 0; ctorNum < paramTypeCtors.Length; ctorNum++)
                        {
                            var ctorParameters = paramTypeCtors[ctorNum].GetParameters();

                            var keyType = ctorParameters[0].ParameterType;
                            var keyNode = elem.Key;
                            this._targetType.Push(keyType);
                            var keyValue = keyNode.Visit(this);
                            this._targetType.Pop();

                            success = keyType.IsInstanceOfType(keyValue);

                            if (success)
                            {
                                var valueType = ctorParameters[1].ParameterType;
                                var valueNode = elem.Value;
                                this._targetType.Push(valueType);
                                var valueValue = valueNode.Visit(this);
                                this._targetType.Pop();

                                success = valueType.IsInstanceOfType(valueValue);

                                if (success)
                                {
                                    success = false;
                                    try
                                    {
                                        object elementObj = paramTypeCtors[ctorNum].Invoke(new[] { keyValue, valueValue });

                                        try
                                        {
                                            addWithOneArgs[addNum].Invoke(ret, new[] { elementObj });
                                            success = true;
                                        }
                                        catch (Exception ex)
                                        {
                                            this.RaiseError(new AddError(addWithOneArgs[addNum],
                                                                            new[] { elementObj },
                                                                            new[] { keyNode, valueNode },
                                                                            ex));
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        this.RaiseError(new ActivationError(paramTypeCtors[ctorNum],
                                                                            new[] {keyValue, valueValue},
                                                                            new[] {keyNode, valueNode},
                                                                            ex));
                                    }

                                    if (success)
                                        break;

                                }
                            }
                        }

                        if (success)
                            break;
                    }
                }
            }

            return ret;
        }
 object IAstVisitor.Visit(AssociativeArray array)
 {
     return Visit(array);
 }