/// <summary> /// Returns the list of columns the materializer would like to have. /// </summary> /// <returns></returns> public override IReadOnlyList <string> DesiredColumns() { if (ConstructorSignature == null) { return(ObjectMetadata.ColumnsFor); } var desiredType = typeof(TObject); var constructor = ObjectMetadata.Constructors.Find(ConstructorSignature); if (constructor == null) { var types = string.Join(", ", ConstructorSignature.Select(t => t.Name)); throw new MappingException($"Cannot find a constructor on {desiredType.Name} with the types [{types}]"); } return(constructor.ParameterNames); }
/// <summary> /// Create an instance of <paramref name="type"/> using constructor with four argument. First matching constructor is used. /// </summary> /// <typeparam name="Arg1T">First argument type.</typeparam> /// <typeparam name="Arg2T">Second argument type.</typeparam> /// <typeparam name="Arg3T">Third argument type.</typeparam> /// <typeparam name="Arg4T">Forth argument type.</typeparam> /// <param name="type">Type of object to create.</param> /// <param name="arg1">Value of first argument.</param> /// <param name="arg2">Value for second argument.</param> /// <param name="arg3">Value for third argument.</param> /// <param name="arg4">Value for forth argument.</param> /// <param name="argCount">Number of arguments.</param> /// <returns>An instance of <paramref name="type"/>.</returns> private static object CreateInstance <Arg1T, Arg2T, Arg3T, Arg4T>(Type type, Arg1T arg1, Arg2T arg2, Arg3T arg3, Arg4T arg4, int argCount) { if (type == null) { throw new ArgumentNullException("type"); } if (argCount < 1 || argCount > 4) { throw new ArgumentOutOfRangeException("argCount"); } var signature = new ConstructorSignature(type, typeof(Arg1T), argCount > 1 ? typeof(Arg2T) : null, argCount > 2 ? typeof(Arg3T) : argCount > 3 ? typeof(Arg4T) : null); #if !NETSTANDARD var typeInfo = type; var constructors = typeInfo.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); #else var typeInfo = type.GetTypeInfo(); var constructors = typeInfo.DeclaredConstructors.ToList(); #endif var constructor = default(Delegate); lock (CustomConstructorCache) { if (CustomConstructorCache.TryGetValue(signature, out constructor) == false) { var foundCtr = default(ConstructorInfo); foreach (var constructorInfo in constructors) { var ctrParams = constructorInfo.GetParameters(); if (ctrParams.Length != argCount) { continue; } if (argCount > 0 && IsAssignableFrom(ctrParams[0].ParameterType, typeof(Arg1T)) == false) { continue; } if (argCount > 1 && IsAssignableFrom(ctrParams[1].ParameterType, typeof(Arg2T)) == false) { continue; } if (argCount > 2 && IsAssignableFrom(ctrParams[2].ParameterType, typeof(Arg3T)) == false) { continue; } if (argCount > 3 && IsAssignableFrom(ctrParams[3].ParameterType, typeof(Arg4T)) == false) { continue; } foundCtr = constructorInfo; break; } if (foundCtr != null) { var ctrParameters = foundCtr.GetParameters(); var arg1Param = Expression.Parameter(typeof(Arg1T), "arg1"); var arg2Param = Expression.Parameter(typeof(Arg2T), "arg2"); var arg3Param = Expression.Parameter(typeof(Arg3T), "arg3"); var arg4Param = Expression.Parameter(typeof(Arg4T), "arg4"); switch (argCount) { case 1: constructor = Expression.Lambda <Func <Arg1T, object> > ( Expression.Convert( Expression.New( foundCtr, Expression.Convert(arg1Param, ctrParameters[0].ParameterType)), typeof(object) ), arg1Param ).Compile(); break; case 2: constructor = Expression.Lambda <Func <Arg1T, Arg2T, object> > ( Expression.Convert( Expression.New( foundCtr, Expression.Convert(arg1Param, ctrParameters[0].ParameterType), Expression.Convert(arg2Param, ctrParameters[1].ParameterType)), typeof(object) ), arg1Param, arg2Param ).Compile(); break; case 3: constructor = Expression.Lambda <Func <Arg1T, Arg2T, Arg3T, object> > ( Expression.Convert( Expression.New( foundCtr, Expression.Convert(arg1Param, ctrParameters[0].ParameterType), Expression.Convert(arg2Param, ctrParameters[1].ParameterType), Expression.Convert(arg3Param, ctrParameters[2].ParameterType)), typeof(object) ), arg1Param, arg2Param, arg3Param ).Compile(); break; case 4: constructor = Expression.Lambda <Func <Arg1T, Arg2T, Arg3T, Arg4T, object> > ( Expression.Convert( Expression.New( foundCtr, Expression.Convert(arg1Param, ctrParameters[0].ParameterType), Expression.Convert(arg2Param, ctrParameters[1].ParameterType), Expression.Convert(arg3Param, ctrParameters[2].ParameterType), Expression.Convert(arg4Param, ctrParameters[3].ParameterType)), typeof(object) ), arg1Param, arg2Param, arg3Param, arg4Param ).Compile(); break; } } CustomConstructorCache[signature] = constructor; } } var instance = default(object); // create instance switch (argCount) { case 1: if (constructor == null) { throw new ArgumentException(string.Format("Type '{0}' does not contains constructor with signature 'ctr({1})'.", type, typeof(Arg1T).Name), "type"); } instance = ((Func <Arg1T, object>)constructor)(arg1); break; case 2: if (constructor == null) { throw new ArgumentException(string.Format("Type '{0}' does not contains constructor with signature 'ctr({1}, {2})'.", type, typeof(Arg1T).Name, typeof(Arg2T).Name), "type"); } instance = ((Func <Arg1T, Arg2T, object>)constructor)(arg1, arg2); break; case 3: if (constructor == null) { throw new ArgumentException(string.Format("Type '{0}' does not contains constructor with signature 'ctr({1}, {2}, {3})'.", type, typeof(Arg1T).Name, typeof(Arg2T).Name, typeof(Arg3T).Name), "type"); } instance = ((Func <Arg1T, Arg2T, Arg3T, object>)constructor)(arg1, arg2, arg3); break; case 4: if (constructor == null) { throw new ArgumentException(string.Format("Type '{0}' does not contains constructor with signature 'ctr({1}, {2}, {3}, {4})'.", type, typeof(Arg1T).Name, typeof(Arg2T).Name, typeof(Arg3T).Name, typeof(Arg4T).Name), "type"); } instance = ((Func <Arg1T, Arg2T, Arg3T, Arg4T, object>)constructor)(arg1, arg2, arg3, arg4); break; } return(instance); }