/// <summary> /// Returns an instance of this <paramref name="type"/>. /// </summary> /// <param name="type">The type an instance of which should be created.</param> /// <param name="arguments">The arguments to pass to the type constructor.</param> /// <returns>An instance of this given <paramref name="type"/>.</returns> /// <exception cref="NotSupportedException">If failed to find a suiting constructor.</exception> public static object GetInstance(this Type type, params object[] arguments) { var factoryKey = new TypeFactoryKey(type, arguments); var typeFactory = _factoriesByType.GetOrAdd(factoryKey, CreateObjectFactory); return(typeFactory.Invoke(arguments)); }
private static Expression GetInstanceCreation( TypeFactoryKey key, Expression lambdaParameters) { var argumentTypes = key.ArgumentTypes; var argumentCount = argumentTypes.Length; if (argumentCount == 0) { return(Expression.New(key.Type)); } // The constructor which matches the given argument types: var instanceTypeCtor = GetMatchingConstructor(key, argumentTypes); // A set of Expressions representing the parameters to pass // to the constructor: var ctorArguments = new Expression[argumentCount]; for (var i = 0; i < argumentCount; ++i) { var argumentType = argumentTypes[i]; // Access the approriate Lambda parameter by index: var lambdaParameter = Expression .ArrayAccess(lambdaParameters, Expression.Constant(i)); // Convert the lambda parameter to the constructor // parameter type if necessary: ctorArguments[i] = argumentType == typeof(object) ? (Expression)lambdaParameter : Expression.Convert(lambdaParameter, argumentType); } // An Expression representing the constructor call, // passing in the constructor parameters: return(Expression.New(instanceTypeCtor, ctorArguments)); }
private static Func <object[], object> CreateObjectFactory(TypeFactoryKey key) { // An Expression representing the parameter to pass // to the Func: var lambdaParameters = Expression.Parameter(typeof(object[]), "params"); // Get an Expression representing the 'new' constructor call: var instanceCreation = GetInstanceCreation(key, lambdaParameters); if (key.Type.IsValueType) { // A value type needs additional boxing: instanceCreation = Expression .Convert(instanceCreation, typeof(object)); } // Compile the Expression into a Func which takes an // object argument array and returns the constructed object: var instanceCreationLambda = Expression .Lambda <Func <object[], object> >(instanceCreation, lambdaParameters); return(instanceCreationLambda.Compile()); }
private static ConstructorInfo GetMatchingConstructor(TypeFactoryKey key, Type[] argumentTypes) { if (!key.HasNullArgumentTypes) { return(key.Type.GetConstructor( Public | Instance, Type.DefaultBinder, CallingConventions.HasThis, argumentTypes, Array.Empty <ParameterModifier>()) ?? throw new NotSupportedException("Failed to find a matching constructor")); } var constructors = key.Type.GetConstructors(Public | Instance); var matchingCtor = default(ConstructorInfo); var parameters = default(ParameterInfo[]); var argumentCount = argumentTypes.Length; for (int i = 0, l = constructors.Length; i < l; ++i) { var constructor = constructors[i]; parameters = constructor.GetParameters(); if (parameters.Length != argumentCount) { continue; } for (var j = 0; j < argumentCount; ++j) { var argumentType = argumentTypes[j]; if ((argumentType != null) && !parameters[j].ParameterType.IsAssignableFrom(argumentType)) { goto NextConstructor; } } if (matchingCtor != null) { throw new NotSupportedException( "Failed to find a single matching constructor due to null arguments"); } matchingCtor = constructor; NextConstructor :; } if (matchingCtor == null) { throw new NotSupportedException( "Failed to find a matching constructor due to null arguments"); } for (var j = 0; j < argumentCount; ++j) { if (argumentTypes[j] == null) { argumentTypes[j] = parameters[j].ParameterType; } } return(matchingCtor); }