private object CoerceList(Type targetType, Type arrayType, IEnumerable value) { if (targetType.IsArray) { return this.CoerceArray(targetType.GetElementType(), value); } // targetType serializes as a JSON array but is not an array // assume is an ICollection / IEnumerable with AddRange, Add, // or custom Constructor with which we can populate it // many ICollection types take an IEnumerable or ICollection // as a constructor argument. look through constructors for // a compatible match. ConstructorInfo[] ctors = targetType.GetConstructors(); ConstructorInfo defaultCtor = null; foreach (ConstructorInfo ctor in ctors) { ParameterInfo[] paramList = ctor.GetParameters(); if (paramList.Length == 0) { // save for in case cannot find closer match defaultCtor = ctor; continue; } if (paramList.Length == 1 && paramList[0].ParameterType.IsAssignableFrom(arrayType)) { try { // invoke first constructor that can take this value as an argument return ctor.Invoke( new object[] { value } ); } catch { // there might exist a better match continue; } } } if (defaultCtor == null) { throw new JsonTypeCoercionException( String.Format(TypeCoercionUtility.ErrorDefaultCtor, targetType.FullName)); } object collection; try { // always try-catch Invoke() to expose real exception collection = defaultCtor.Invoke(null); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException); } throw new JsonTypeCoercionException("Error instantiating " + targetType.FullName, ex); } // many ICollection types have an AddRange method // which adds all items at once MethodInfo method = targetType.GetMethod("AddRange"); ParameterInfo[] parameters = (method == null) ? null : method.GetParameters(); Type paramType = (parameters == null || parameters.Length != 1) ? null : parameters[0].ParameterType; if (paramType != null && paramType.IsAssignableFrom(arrayType)) { try { // always try-catch Invoke() to expose real exception // add all members in one method method.Invoke( collection, new object[] { value }); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException); } throw new JsonTypeCoercionException("Error calling AddRange on " + targetType.FullName, ex); } return collection; } else { // many ICollection types have an Add method // which adds items one at a time method = targetType.GetMethod("Add"); parameters = (method == null) ? null : method.GetParameters(); paramType = (parameters == null || parameters.Length != 1) ? null : parameters[0].ParameterType; if (paramType != null) { // loop through adding items to collection foreach (object item in value) { try { // always try-catch Invoke() to expose real exception method.Invoke( collection, new object[] { this.CoerceType(paramType, item) }); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException); } throw new JsonTypeCoercionException("Error calling Add on " + targetType.FullName, ex); } } return collection; } } try { // fall back to basics return Convert.ChangeType(value, targetType); } catch (Exception ex) { throw new JsonTypeCoercionException(String.Format("Error converting {0} to {1}", value.GetType().FullName, targetType.FullName), ex); } }
public static MethodInfo GetMethod (Type type, MethodInfo method) { if (!IsValidGetMethodType (type)) throw new ArgumentException ("type is not TypeBuilder but " + type.GetType (), "type"); if (type is TypeBuilder && type.ContainsGenericParameters) type = type.MakeGenericType (type.GetGenericArguments ()); if (!type.IsGenericType) throw new ArgumentException ("type is not a generic type", "type"); if (!method.DeclaringType.IsGenericTypeDefinition) throw new ArgumentException ("method declaring type is not a generic type definition", "method"); if (method.DeclaringType != type.GetGenericTypeDefinition ()) throw new ArgumentException ("method declaring type is not the generic type definition of type", "method"); if (method == null) throw new NullReferenceException (); //MS raises this instead of an ArgumentNullException MethodInfo res = type.GetMethod (method); if (res == null) throw new ArgumentException (String.Format ("method {0} not found in type {1}", method.Name, type)); return res; }