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); }