public Expression <GenericPropertySetter> BuildGenericSetter(PropertyInfo propertyInfo) { var setMethod = ValidatePropertyAndGetAccessorMethod(propertyInfo, null, false); if (EnableCaching && genericSetterCache.TryGetValue(propertyInfo, out var cachedLambda)) { return((Expression <GenericPropertySetter>)cachedLambda); } var instanceParameter = Expression.Parameter(typeof(object), "instance"); var inputParameters = Expression.Parameter(typeof(object[]), "indexers"); var valueParameter = Expression.Parameter(typeof(object), "value"); var methodCallParameters = propertyInfo.GetIndexParameters() .Select((x, i) => ExpressionEx.ConvertIfNeeded( Expression.ArrayAccess(inputParameters, Expression.Constant(i)), x.ParameterType)) .Concat(new[] { ExpressionEx.ConvertIfNeeded(valueParameter, propertyInfo.PropertyType) }); var invokerExpression = Expression.Call( setMethod.IsStatic ? null : ExpressionEx.ConvertIfNeeded(instanceParameter, setMethod.DeclaringType), setMethod, methodCallParameters); var lambda = Expression.Lambda <GenericPropertySetter>(invokerExpression, new[] { instanceParameter, valueParameter, inputParameters }); if (EnableCaching) { genericSetterCache.TryAdd(propertyInfo, lambda); } return(lambda); }
private CompiledDynamicProjectionConfiguration Compile() { configuration.ProjectedType = configuration.ProjectedType ?? #if NETSTANDARD2_0 throw new InvalidOperationException("Projected type not set. Dynamic type building in not supported in net standard."); #else BuildProjectedType(); #endif configuration.Ctor = configuration.Ctor ?? FindMatchingConstructor(); if (configuration.Ctor == null) { throw new InvalidOperationException($"No matching constructor found for type {configuration.ProjectedType.Name}"); } var compiledMembers = configuration.Members.Select(x => (Configuration: x, CompiledMember: CompileMember(x))).ToList(); var compiledCtorParams = configuration.CtorParameters.Select(x => (Configuration: x, CompiledCtorParam: CompileCtorParameter(x))).ToList(); var compiledMemberTargets = compiledMembers.Select(x => new CompiledMemberTargetConfiguration(x.CompiledMember, CompileMemberSource(x.CompiledMember, x.Configuration))).ToList(); var compiledCtorParamTargets = compiledCtorParams.Select(x => new CompiledCtorParamTargetConfiguration(x.CompiledCtorParam, CompileCtorParameterSource(x.CompiledCtorParam, x.Configuration))).ToList(); var ctorParameterAssignments = configuration.Ctor.GetParameters().Select(p => compiledCtorParamTargets .Where(x => x.CtorParameter.ParameterInfo.Name == p.Name) .Select(x => new CtorParameterAssignment(null, x.Source.SourceExpression)) .FirstOrDefault() ?? compiledMemberTargets .Where(x => x.Member.ProjectionTarget == ProjectionTarget.CtorParameter && x.Member.CtorParameterName == p.Name) .Select(x => new CtorParameterAssignment(x.Member.MemberInfo.Name, x.Source.SourceExpression)) .FirstOrDefault() ?? (p.HasDefaultValue ? new CtorParameterAssignment(null, Expression.Constant(p.DefaultValue)) : throw new InvalidOperationException($"No source given for non optional constructor parameter {p.Name} on type {configuration.ProjectedType.Name}"))) .ToList(); var memberInitAssignments = compiledMemberTargets .Where(x => x.Member.ProjectionTarget == ProjectionTarget.Member) .Select(p => new MemberInitAssignment( memberName: p.Member.MemberInfo.Name, memberAssignement: Expression.Bind( p.Member.MemberInfo, ExpressionEx.ConvertIfNeeded(p.Source.SourceExpression, p.Member.MemberType)))) .ToList(); var defaultProjection = Expression.Lambda( Expression.MemberInit( Expression.New(configuration.Ctor, ctorParameterAssignments.Select(x => x.SourceExpression)), memberInitAssignments.Select(x => x.MemberAssignement)), configuration.It); return(new CompiledDynamicProjectionConfiguration( configuration, compiledCtorParamTargets, compiledMemberTargets, memberInitAssignments, ctorParameterAssignments, defaultProjection)); }
public Expression <Func <object, object> > BuildGenericGetter(FieldInfo fieldInfo) { ValidateField(fieldInfo, null); if (EnableCaching && genericGetterCache.TryGetValue(fieldInfo, out var cachedLambda)) { return((Expression <Func <object, object> >)cachedLambda); } var instanceParameter = Expression.Parameter(typeof(object), "instance"); var invokerExpression = Expression.Field( fieldInfo.IsStatic ? null : ExpressionEx.ConvertIfNeeded(instanceParameter, fieldInfo.DeclaringType), fieldInfo); var body = ExpressionEx.CastTypeSafe(invokerExpression, typeof(object)); var lambda = Expression.Lambda <Func <object, object> >(body, instanceParameter); if (EnableCaching) { genericGetterCache.TryAdd(fieldInfo, lambda); } return(lambda); }
private static Expression BuildKeyValueSelectorExpression(Type entityType, List <PropertyInfo> keyProperties, out ParameterExpression entityParameterExpression, out Type keyValueType) { entityParameterExpression = Expression.Parameter(typeof(object)); var convertedEntityTypeExpression = ExpressionEx.ConvertIfNeeded(entityParameterExpression, entityType); if (!keyProperties.Any()) { keyProperties = entityType.GetProperties().ToList(); } if (keyProperties.Count == 1) { var property = keyProperties.Single(); keyValueType = property.PropertyType; return(Expression.Property(convertedEntityTypeExpression, property)); } else { keyValueType = BuildKeyValueType(entityType, keyProperties); var keyValueTypeCtor = keyValueType.GetConstructors().First(x => x.GetParameters().Length > 0); return(Expression.New( constructor: keyValueTypeCtor, arguments: keyProperties .Select(x => Expression.Property(convertedEntityTypeExpression, x)) .ToArray() )); } }
public Expression <GenericStaticInvoker> BuildGeneric(ConstructorInfo ctorInfo) { if (ctorInfo == null) { throw new ArgumentNullException(nameof(ctorInfo)); } if (EnableCaching && genericCache.TryGetValue(ctorInfo, out var cachedLambda)) { return((Expression <GenericStaticInvoker>)cachedLambda); } var inputParameters = Expression.Parameter(typeof(object[]), "parameters"); var methodParameters = ctorInfo.GetParameters(); var methodCallParameters = methodParameters .Select((x, i) => ExpressionEx.ConvertIfNeeded( Expression.ArrayAccess(inputParameters, Expression.Constant(i)), x.ParameterType)); var invokerExpression = Expression.New( ctorInfo, methodCallParameters); var body = ExpressionEx.CastTypeSafe(invokerExpression, typeof(object)); var lambda = Expression.Lambda <GenericStaticInvoker>(body, new[] { inputParameters }); if (EnableCaching) { genericCache.TryAdd(ctorInfo, lambda); } return(lambda); }
private static Expression BuildSetKeyConstructorExpression(Type keyType, Type keyValueType, Expression keyValueSelectorExpression) { var keyCtorSet = keyType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { keyValueType }, null); return(Expression.New( constructor: keyCtorSet, arguments: ExpressionEx.ConvertIfNeeded(keyValueSelectorExpression, keyValueType))); }
public static Func <object, object> BuildKeyValueSelector(Type type, IEnumerable <PropertyInfo> keyPropertiesEnumerable) { var keyProperties = keyPropertiesEnumerable is List <PropertyInfo> keyPropertiesList ? keyPropertiesList : keyPropertiesEnumerable.ToList(); var selector = BuildKeyValueSelectorExpression(type, keyProperties, out var parameter, out var _); var body = ExpressionEx.ConvertIfNeeded(selector, typeof(object)); return(Expression.Lambda <Func <object, object> >(body, parameter).Compile()); }
public Expression <Action <object, object> > BuildGenericSetter(FieldInfo fieldInfo) { ValidateField(fieldInfo, null); if (EnableCaching && genericSetterCache.TryGetValue(fieldInfo, out var cachedLambda)) { return((Expression <Action <object, object> >)cachedLambda); } var instanceParameter = Expression.Parameter(typeof(object), "instance"); var value = Expression.Parameter(typeof(object), "value"); var castedInstance = ExpressionEx.ConvertIfNeeded(instanceParameter, fieldInfo.DeclaringType); Expression <Action <object, object> > lambda; if (!fieldInfo.IsInitOnly) { lambda = Expression.Lambda <Action <object, object> >( Expression.Assign( Expression.Field(fieldInfo.IsStatic ? null : castedInstance, fieldInfo), GetCastedValueExpression(value, fieldInfo.FieldType)), instanceParameter, value); } else { #if !NETSTANDARD2_0 var m = Reflection.Emit.FieldAccessorMethodEmitter.GetFieldSetterMethod(fieldInfo, GenericTypeExtensions.GetActionGenericType(fieldInfo.DeclaringType, fieldInfo.FieldType)); lambda = Expression.Lambda <Action <object, object> >( Expression.Call(m, castedInstance, GetCastedValueExpression(value, fieldInfo.FieldType)), instanceParameter, value); #else throw new InvalidOperationException($"Field {fieldInfo.Name} is InitOnly and cannot be set."); #endif } if (EnableCaching) { genericGetterCache.TryAdd(fieldInfo, lambda); } return(lambda); }
public LambdaExpression CreateSelector(Type ModelType, Type returnType = null, IEnumerable <string> includedProperties = null) { var inParam = Expression.Parameter(ModelType, "model"); if (returnType == null) { returnType = GetReturnType("tmpDynamicDTO_" + random.Next().ToString()); } var memberAssignments = new List <MemberAssignment>(); foreach (var p in (includedProperties == null ? props : props.Where(x => includedProperties.Any(ip => StringComparer.OrdinalIgnoreCase.Compare(ip, x.TargetProperty ?? x.PropertyName) == 0)))) { Expression memberExpression; var exp = p.SourceExpression; if (exp == null) { memberExpression = Expression.Property(CreateMemberExpression(inParam, p.PropertyPath), p.PropertyName); } else { var memberlambda = (LambdaExpression) new SelectorToExpressionVisitor().Modify( exp, exp.Parameters[0], CreateMemberExpression(inParam, p.PropertyPath)); memberExpression = memberlambda.Body; } var targetProperty = returnType.GetProperty(p.TargetProperty); memberAssignments.Add( Expression.Bind( targetProperty, ExpressionEx.ConvertIfNeeded(memberExpression, targetProperty.PropertyType) )); } var init = Expression.MemberInit(Expression.New(returnType), memberAssignments); return(Expression.Lambda(init, inParam)); }
public static Func <object, object> BuildKeySelector(Type entityType, IEnumerable <PropertyInfo> keyPropertiesEnumerable) { var keyProperties = keyPropertiesEnumerable is List <PropertyInfo> keyPropertiesList ? keyPropertiesList : keyPropertiesEnumerable.ToList(); var valueSelectorExpression = BuildKeyValueSelectorExpression(entityType, keyProperties, out var entityParameterExpression, out var keyValueType); var keyType = typeof(DomainKey <>).MakeGenericTypeCached(keyValueType); var entityExpression = ExpressionEx.ConvertIfNeeded(entityParameterExpression, entityType); var keySetCtorExpression = BuildSetKeyConstructorExpression(keyType, keyValueType, valueSelectorExpression); var keyUnSetCtorExpression = BuildUnSetKeyConstructorExpression(keyType, entityExpression); var isKeySetExpresion = Expression.Call(entityExpression, nameof(DummyEntity.GetKeyIsAssigned), new Type[0], new Expression[0]); var body = Expression.Condition( test: Expression.Equal(isKeySetExpresion, ExpressionEx.Constants.True), ifTrue: keySetCtorExpression, ifFalse: keyUnSetCtorExpression ); return(Expression.Lambda <Func <object, object> >(ExpressionEx.ConvertIfNeeded(body, typeof(object)), entityParameterExpression).Compile()); }
private Expression BuildEnumPredicate() { if (DataType != PredicateDataType.Enum) { return(null); } var value = NumericTypeHelper.AsNumericFromEnum(Value, EffectiveType, out var comparableType); var left = Expression; if (IsNullableType) { left = Expression.Property(left, nameof(Nullable <int> .Value)); } left = ExpressionEx.ConvertIfNeeded(left, comparableType); var right = Expression.Constant(value); return(BuildEquitableExpression(left, Operator, right) ?? BuildComparableExpression(left, Operator, right)); }
private Expression BuildNumericPredicate() { if (DataType != PredicateDataType.Number) { return(null); } var value = NumericTypeHelper.AsNumeric(Value, EffectiveType, Configuration.NumberStyles, Configuration.FormatProvider, out var comparableType); var left = Expression; if (numericTypeDescriptor.Nullable) { left = Expression.Property(Expression, nameof(Nullable <int> .Value)); } left = ExpressionEx.ConvertIfNeeded(left, comparableType); var right = Expression.Constant(value); return(BuildEquitableExpression(left, Operator, right) ?? BuildComparableExpression(left, Operator, right)); }
internal LambdaExpression BuildGenericInvoker(MethodInfo methodInfo, bool asInstance = false) { CacheKey cacheKey = null; if (EnableCaching) { cacheKey = new CacheKey(methodInfo, asInstance); if (genericCache.TryGetValue(cacheKey, out var cachedLambda)) { return(cachedLambda); } } var instanceParameter = Expression.Parameter(typeof(object), "instance"); var inputParameters = Expression.Parameter(typeof(object[]), "parameters"); var methodParameters = methodInfo.GetParameters(); var methodInstanceParameters = methodParameters .Skip(asInstance && methodInfo.IsExtension() ? 1 : 0) .ToList(); var byRefVariables = methodInstanceParameters .Select((x, i) => new { Index = i, Parameter = x }) .Where(x => x.Parameter.ParameterType.IsByRef) .Select(x => new { x.Index, Variable = Expression.Variable(x.Parameter.ParameterType.GetElementType(), x.Parameter.Name) }) .ToArray(); var methodCallParameters = methodInstanceParameters .Select((x, i) => ExpressionEx.ConvertIfNeeded( x.ParameterType.IsByRef ? (Expression)byRefVariables.Single(v => v.Index == i).Variable : (Expression)Expression.ArrayAccess(inputParameters, Expression.Constant(i)), x.ParameterType)) .ToList(); Expression invokerExpression; ParameterExpression[] expressionParameters; Type delegateType; //Instance if (!methodInfo.IsStatic) { invokerExpression = Expression.Call( ExpressionEx.ConvertIfNeeded(instanceParameter, methodInfo.DeclaringType), methodInfo, methodCallParameters); expressionParameters = new[] { instanceParameter, inputParameters }; delegateType = typeof(GenericInstanceInvoker); } //Extension as Instance else if (asInstance && methodInfo.IsExtension()) { invokerExpression = Expression.Call( methodInfo, new Expression[] { ExpressionEx.ConvertIfNeeded(instanceParameter, methodParameters[0].ParameterType) }.Concat(methodCallParameters)); expressionParameters = new[] { instanceParameter, inputParameters }; delegateType = typeof(GenericInstanceInvoker); } //Static as Instance else if (asInstance && methodInfo.IsStatic) { invokerExpression = Expression.Call( methodInfo, methodCallParameters); expressionParameters = new[] { instanceParameter, inputParameters }; delegateType = typeof(GenericInstanceInvoker); } //Static else { invokerExpression = Expression.Call( methodInfo, methodCallParameters); expressionParameters = new[] { inputParameters }; delegateType = typeof(GenericStaticInvoker); } var isFunc = methodInfo.ReturnType != typeof(void); var byRefAssignmentsFromArray = byRefVariables .Select(x => (Expression)Expression.Assign(x.Variable, ExpressionEx.ConvertIfNeeded( Expression.ArrayAccess(inputParameters, Expression.Constant(x.Index)), x.Variable.Type))); var byRefAssignmentsToArray = byRefVariables .Select(x => (Expression)Expression.Assign(Expression.ArrayAccess(inputParameters, Expression.Constant(x.Index)), ExpressionEx.ConvertIfNeeded(x.Variable, typeof(object)))); var returnVariable = isFunc && byRefVariables.Any() ? Expression.Variable(methodInfo.ReturnType) : null; var declaredVariables = (returnVariable != null ? new[] { returnVariable } : Enumerable.Empty <ParameterExpression>()) .Concat(byRefVariables.Select(x => x.Variable)) .ToArray(); var invokerBody = Enumerable.Empty <Expression>() .Concat(byRefAssignmentsFromArray) .Concat(returnVariable != null ? new[] { Expression.Assign(returnVariable, invokerExpression) } : new[] { invokerExpression }) .Concat(byRefAssignmentsToArray) .Concat(returnVariable != null ? new[] { returnVariable } : Enumerable.Empty <Expression>()); if (!isFunc) { invokerBody = invokerBody.Concat(new Expression[] { Expression.Constant(null) }); } //If is Action, return null as object //Else if is Func return actual type and cast to object var body = (!isFunc) ? Expression.Block(typeof(object), declaredVariables, invokerBody) : ExpressionEx.ConvertIfNeeded( Expression.Block(methodInfo.ReturnType, declaredVariables, invokerBody), typeof(object)); var lambda = Expression.Lambda(delegateType, body, expressionParameters); if (EnableCaching) { genericCache.TryAdd(cacheKey, lambda); } return(lambda); }
private LambdaExpression BuildInvokerExpressionFromTypes(MethodInfo methodInfo, Type instanceType, IEnumerable <Type> parameterTypes, Type returnType, Type delegateType) { if (methodInfo == null) { throw new ArgumentNullException(nameof(methodInfo)); } CacheKey cacheKey = null; if (EnableCaching && delegateType != null) { cacheKey = new CacheKey(methodInfo, instanceType, returnType, parameterTypes); if (byTypesCache.TryGetValue(cacheKey, out var cachedLambda)) { return(cachedLambda); } } returnType = returnType ?? methodInfo.ReturnType; instanceType = methodInfo.IsStatic ? null : instanceType ?? methodInfo.DeclaringType; var methodParameters = (methodInfo.IsStatic ? Enumerable.Empty <MethodParameter>() : new[] { new MethodParameter { InputParameter = Expression.Parameter(instanceType, "instance"), MethodType = methodInfo.DeclaringType } }) .Concat(methodInfo.GetParameters().ZipOutter(parameterTypes ?? Enumerable.Empty <Type>(), (mp, pt) => new MethodParameter { InputParameter = Expression.Parameter(pt ?? mp.ParameterType, mp.Name), MethodType = mp.ParameterType })) .Select(x => new { x.InputParameter, MethodCallParameter = x.MethodType == x.InputParameter.Type ? (Expression)x.InputParameter : ExpressionEx.ConvertIfNeeded(x.InputParameter, x.MethodType) }) .ToList(); var isAction = methodInfo.ReturnType == typeof(void) && (returnType == null || returnType == typeof(void)); var effectiveDelegateType = delegateType ?? (isAction ? GenericTypeExtensions.GetActionGenericType(methodParameters.Select(x => x.MethodCallParameter.Type)) : GenericTypeExtensions.GetFuncGenericType(methodParameters.Select(x => x.MethodCallParameter.Type).Concat(new[] { returnType }).ToArray())); var invokerExpression = Expression.Call( methodInfo.IsStatic ? null : methodParameters.Select(x => x.MethodCallParameter).First(), methodInfo, methodParameters.Select(x => x.MethodCallParameter).Skip(methodInfo.IsStatic ? 0 : 1)); var body = methodInfo.ReturnType == typeof(void) ? (!isAction ? (Expression)Expression.Block(typeof(object), invokerExpression, Expression.Constant(null)) : invokerExpression) : Expression.Convert(invokerExpression, returnType); var lambda = Expression.Lambda(effectiveDelegateType, body, methodParameters.Select(x => x.InputParameter)); if (EnableCaching && delegateType != null) { byTypesCache.TryAdd(cacheKey, lambda); } return(lambda); }
private LambdaExpression BuildFromTypes(ConstructorInfo ctorInfo, Type instanceType, IEnumerable <Type> parameterTypes, Type delegateType) { CacheKey cacheKey = null; if (EnableCaching && delegateType == null) { cacheKey = new CacheKey(ctorInfo, instanceType, parameterTypes); if (cache.TryGetValue(cacheKey, out var lambda)) { return(lambda); } } var effectiveInstanceType = instanceType ?? ctorInfo.DeclaringType; var constructorParameters = ctorInfo.GetParameters() .ZipOutter(parameterTypes ?? Enumerable.Empty <Type>(), (cp, p) => new { MethodType = cp.ParameterType, Name = cp.Name, InputParameter = Expression.Parameter(p ?? cp.ParameterType, cp.Name), }) .Select(x => new { x.InputParameter, MethodCallParameter = x.MethodType == x.InputParameter.Type ? (Expression)x.InputParameter : ExpressionEx.ConvertIfNeeded(x.InputParameter, x.MethodType) }) .ToList(); var effectiveDelegateType = delegateType ?? GenericTypeExtensions.GetFuncGenericType(constructorParameters.Select(x => x.InputParameter.Type).Concat(new[] { effectiveInstanceType })); var invokerExpression = (Expression)Expression.New(ctorInfo, constructorParameters.Select(x => x.MethodCallParameter)); if (effectiveInstanceType != ctorInfo.DeclaringType) { invokerExpression = Expression.Convert(invokerExpression, effectiveInstanceType); } var l = Expression.Lambda(effectiveDelegateType, invokerExpression, constructorParameters.Select(x => x.InputParameter).ToArray()); if (EnableCaching && delegateType == null) { cache.TryAdd(cacheKey, l); } return(l); }