private static MethodMap DetermineBestMatch(IEnumerable <MethodBase> methods, bool mustUseAllParameters, string[] paramNames, Type[] parameterTypes, object[] sampleParamValues) { MethodMap bestMap = null; foreach (MethodBase method in methods) { MethodMap map = CreateMap(method, paramNames, parameterTypes, sampleParamValues, mustUseAllParameters); if (map != null && map.IsValid) { bool isBetter = bestMap == null; isBetter |= map.IsPerfectMatch; isBetter |= bestMap != null && (map.Cost < bestMap.Cost || (map.Cost == bestMap.Cost && map.RequiredParameterCount > bestMap.RequiredParameterCount)); isBetter &= map.IsValid; if (isBetter) { bestMap = map; } } } if (bestMap != null) { bestMap.InitializeInvoker(); return(bestMap); } return(null); }
public static MethodMap PrepareInvoke(Type type, string[] paramNames, Type[] parameterTypes, object[] sampleParamValues) { SourceInfo sourceInfo = new SourceInfo(type, paramNames, parameterTypes); MethodMap map = ctorMapCache.Get(sourceInfo); if (map == null) { map = DetermineBestConstructorMatch(type, paramNames, parameterTypes, sampleParamValues); ctorMapCache.Insert(sourceInfo, map); } return(map); }
/// <summary> /// Creates an instance of the given <paramref name="type"/> using the public properties of the /// supplied <paramref name="sample"/> object as input. /// This method will try to determine the least-cost route to constructing the instance, which /// implies mapping as many properties as possible to constructor parameters. Remaining properties /// on the source are mapped to properties on the created instance or ignored if none matches. /// TryCreateInstance is very liberal and attempts to convert values that are not otherwise /// considered compatible, such as between strings and enums or numbers, Guids and byte[], etc. /// </summary> /// <returns>An instance of <paramref name="type"/>.</returns> public static object TryCreateInstance(this Type type, object sample) { Type sourceType = sample.GetType(); SourceInfo sourceInfo = sourceInfoCache.Get(sourceType); if (sourceInfo == null) { sourceInfo = new SourceInfo(sourceType); sourceInfoCache.Insert(sourceType, sourceInfo); } object[] paramValues = sourceInfo.GetParameterValues(sample); MethodMap map = MapFactory.PrepareInvoke(type, sourceInfo.ParamNames, sourceInfo.ParamTypes, paramValues); return(map.Invoke(paramValues)); }
/// <summary> /// Creates an instance of the given <paramref name="type"/> using the supplied parameter information as input. /// This method will try to determine the least-cost route to constructing the instance, which /// implies mapping as many properties as possible to constructor parameters. Remaining properties /// on the source are mapped to properties on the created instance or ignored if none matches. /// TryCreateInstance is very liberal and attempts to convert values that are not otherwise /// considered compatible, such as between strings and enums or numbers, Guids and byte[], etc. /// </summary> /// <param name="type">The type of which an instance should be created.</param> /// <param name="parameterNames">The names of the supplied parameters.</param> /// <param name="parameterTypes">The types of the supplied parameters.</param> /// <param name="parameterValues">The values of the supplied parameters.</param> /// <returns>An instance of <paramref name="type"/>.</returns> public static object TryCreateInstance(this Type type, string[] parameterNames, Type[] parameterTypes, object[] parameterValues) { var names = parameterNames ?? new string[0]; var types = parameterTypes ?? new Type[0]; var values = parameterValues ?? new object[0]; if (names.Length != values.Length || names.Length != types.Length) { throw new ArgumentException("Mismatching name, type and value arrays (must be of identical length)."); } MethodMap map = MapFactory.PrepareInvoke(type, names, types, values); return(map.Invoke(values)); }
internal static MethodMap DetermineBestConstructorMatch(Type type, string[] paramNames, Type[] parameterTypes, object[] sampleParamValues) { MethodMap map = DetermineBestMatch(type.GetConstructors(), false, paramNames, parameterTypes, sampleParamValues); if (map != null) { return(map); } StringBuilder sb = new StringBuilder(); sb.AppendFormat("No constructor found for type {0} using parameters:{1}", type.Name, Environment.NewLine); sb.AppendFormat("{0}{1}", string.Join(", ", Enumerable.Range(0, paramNames.Length).Select(i => string.Format("{0}:{1}", paramNames[i], parameterTypes[i])).ToArray()), Environment.NewLine); throw new MissingMethodException(sb.ToString()); }
internal static MethodMap DetermineBestMethodMatch(IEnumerable <MethodBase> methods, bool mustUseAllParameters, string[] paramNames, Type[] parameterTypes, object[] sampleParamValues) { MethodMap map = DetermineBestMatch(methods, mustUseAllParameters, paramNames, parameterTypes, sampleParamValues); if (map != null) { return(map); } StringBuilder sb = new StringBuilder(); sb.AppendFormat("No method found ({0} candidates examined) matching the parameters:{1}", methods.ToList().Count, Environment.NewLine); //sb.AppendFormat("{0}{1}", Format(parameters, "=", ", "), Environment.NewLine); sb.AppendFormat("{0}{1}", string.Join(", ", Enumerable.Range(0, paramNames.Length).Select(i => string.Format("{0}:{1}", paramNames[i], parameterTypes[i])).ToArray()), Environment.NewLine); throw new MissingMethodException(sb.ToString()); }
/// <summary> /// Obtains a list of all methods with the given <paramref name="methodName"/> on the given /// <paramref name="obj" />, and invokes the best match for the supplied parameters. /// TryCallMethod is very liberal and attempts to convert values that are not otherwise /// considered compatible, such as between strings and enums or numbers, Guids and byte[16], etc. /// </summary> /// <param name="obj">The type of which an instance should be created.</param> /// <param name="methodName">The name of the overloaded methods.</param> /// <param name="mustUseAllParameters">Specifies whether all supplied parameters must be used in the /// invocation. Unless you know what you are doing you should pass true for this parameter.</param> /// <param name="parameterNames">The names of the supplied parameters.</param> /// <param name="parameterTypes">The types of the supplied parameters.</param> /// <param name="parameterValues">The values of the supplied parameters.</param> /// <returns>The result of the invocation.</returns> public static object TryCallMethod(this object obj, string methodName, bool mustUseAllParameters, string[] parameterNames, Type[] parameterTypes, object[] parameterValues) { bool isStatic = obj is Type; var type = isStatic ? obj as Type : obj.GetType(); var names = parameterNames ?? new string[0]; var types = parameterTypes ?? new Type[0]; var values = parameterValues ?? new object[0]; if (names.Length != values.Length || names.Length != types.Length) { throw new ArgumentException("Mismatching name, type and value arrays (must be of identical length)."); } MethodMap map = MapFactory.DetermineBestMethodMatch(type.Methods(methodName).Cast <MethodBase>(), mustUseAllParameters, names, types, values); return(isStatic ? map.Invoke(values) : map.Invoke(obj, values)); }