/// <summary> /// 解决 对象 到 类似 ICollection<KeyValuePair<TKey,TValue>> 类型的转换。 /// </summary> /// <typeparam name="TResult">目标类型。</typeparam> /// <param name="sourceType">源类型。</param> /// <param name="conversionType">目标类型。</param> /// <param name="typeArgument">泛型【KeyValuePair<TKey,TValue>】约束。</param> /// <param name="typeArguments">泛型【TKey,TValue】约束。</param> /// <returns></returns> protected override Func <object, TResult> ByObjectToICollectionKeyValuePair <TResult>(Type sourceType, Type conversionType, Type typeArgument, Type[] typeArguments) { var typeStore = TypeItem.Get(sourceType); var list = new List <Expression>(); var listKvType = typeof(List <>).MakeGenericType(typeArgument); var resultExp = Variable(listKvType); var targetExp = Variable(sourceType); var sourceExp = Parameter(typeof(object)); var method = listKvType.GetMethod("Add", new Type[] { typeArgument }); list.Add(Assign(targetExp, Convert(sourceExp, sourceType))); var methodCtor = ServiceCtor.Method; var bodyExp = methodCtor.IsStatic ? Call(null, methodCtor, Constant(listKvType)) : Call(Constant(ServiceCtor.Target), methodCtor, Constant(listKvType)); list.Add(Assign(resultExp, Convert(bodyExp, listKvType))); var typeStore2 = TypeItem.Get(typeArgument); var ctorSotre = typeStore2.ConstructorStores.Where(x => x.ParameterStores.Count == 2).First(); if (Kind == PatternKind.Property || Kind == PatternKind.All) { typeStore.PropertyStores .Where(x => x.CanRead) .ForEach(info => { list.Add(Call(resultExp, method, New(ctorSotre.Member, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Property(targetExp, info.Member), typeArguments[1])))); }); } if (Kind == PatternKind.Field || Kind == PatternKind.All) { typeStore.FieldStores .Where(x => x.CanRead) .ForEach(info => { list.Add(Call(resultExp, method, New(ctorSotre.Member, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Field(targetExp, info.Member), typeArguments[1])))); }); } list.Add(Convert(resultExp, conversionType)); var lamdaExp = Lambda <Func <object, TResult> >(Block(new[] { targetExp, resultExp }, list), sourceExp); return(lamdaExp.Compile()); }
/// <summary> /// 解决 IEnumarable<T> 到 泛型约束类的转换。 /// </summary> /// <typeparam name="TResult">目标类型。</typeparam> /// <param name="sourceType">源类型。</param> /// <param name="conversionType">目标类型。</param> /// <param name="interfaceType">接口类型。</param> /// <param name="typeArguments">方向约束。</param> /// <returns></returns> protected virtual Func <object, TResult> ByEnumarableKeyValuePairToObject <TResult>(Type sourceType, Type conversionType, Type interfaceType, Type[] typeArguments) { var typeStore = TypeItem.Get(conversionType); if (typeStore.ConstructorStores.Any(x => x.ParameterStores.Count == 0)) { return(ByEnumarableKeyValuePairToCommon <TResult>(typeStore, sourceType, conversionType, interfaceType, typeArguments)); } return(ByEnumarableKeyValuePairToComplex <TResult>(typeStore, sourceType, conversionType, interfaceType, typeArguments)); }
/// <summary> /// 解决 对象 到类似 IDictionary<TKey,TValue> 的转换。 /// </summary> /// <typeparam name="TResult">目标类型。</typeparam> /// <param name="sourceType">源类型。</param> /// <param name="conversionType">目标类型。</param> /// <param name="typeArguments">泛型【TKey,TValue】约束。</param> /// <returns></returns> protected override Func <object, TResult> ByObjectToDictionaryLike <TResult>(Type sourceType, Type conversionType, Type[] typeArguments) { var typeStore = TypeItem.Get(sourceType); var list = new List <Expression>(); var resultExp = Variable(conversionType); var targetExp = Variable(sourceType); var sourceExp = Parameter(typeof(object)); var method = conversionType.GetMethod("Add", typeArguments); list.Add(Assign(targetExp, Convert(sourceExp, sourceType))); var methodCtor = ServiceCtor.Method; var bodyExp = methodCtor.IsStatic ? Call(null, methodCtor, Constant(conversionType)) : Call(Constant(ServiceCtor.Target), methodCtor, Constant(conversionType)); list.Add(Assign(resultExp, Convert(bodyExp, conversionType))); if (Kind == PatternKind.Property || Kind == PatternKind.All) { typeStore.PropertyStores .Where(x => x.CanRead) .ForEach(info => { list.Add(Call(resultExp, method, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Property(targetExp, info.Member), typeArguments[1]))); }); } if (Kind == PatternKind.Field || Kind == PatternKind.All) { typeStore.FieldStores .Where(x => x.CanRead) .ForEach(info => { list.Add(Call(resultExp, method, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Field(targetExp, info.Member), typeArguments[1]))); }); } list.Add(resultExp); var lamdaExp = Lambda <Func <object, TResult> >(Block(new[] { targetExp, resultExp }, list), sourceExp); return(lamdaExp.Compile()); }
/// <summary> /// 映射查询(生成“<typeparamref name="TResult"/>”类型的查询表达式)。 /// 注:名称相同(支持<see cref="NamingAttribute"/>比较),且可读写的属性映射。如:x => new YueClass { Id = x.Id, Name = x.Name }。 /// </summary> /// <typeparam name="TResult">查询结果。</typeparam> /// <param name="source">数据源。</param> /// <returns></returns> public static IQueryable <TResult> Map <TResult>(this IQueryable source) where TResult : class, new() { if (source is IQueryable <TResult> queryable) { return(queryable); } var conversionType = typeof(TResult); var elementType = source.ElementType; return(source.Provider.CreateQuery <TResult>(Expressions.GetOrAdd(((long)elementType.MetadataToken << 31) + conversionType.MetadataToken, _ => { var typeItem = TypeItem.Get(conversionType); var typeItem2 = TypeItem.Get(elementType); var parameterExp = Parameter(elementType, "x"); var list = new List <MemberBinding>(); typeItem.PropertyStores .Where(x => x.CanWrite && x.CanRead) .ForEach(x => { var propItem = typeItem2.PropertyStores .FirstOrDefault(y => y.Name == x.Name && y.MemberType == x.MemberType && y.CanRead) ?? typeItem2 .PropertyStores.FirstOrDefault(y => y.MemberType == x.MemberType && y.CanRead && y.Naming == x.Naming) ?? typeItem2 .PropertyStores.FirstOrDefault(y => y.MemberType == x.MemberType && y.CanRead && y.Name == x.Naming) ?? typeItem2 .PropertyStores.FirstOrDefault(y => y.MemberType == x.MemberType && y.CanRead && y.Naming == x.Name); if (propItem is null || propItem.Ignore) { return; } list.Add(Bind(x.Member, Property(parameterExp, propItem.Member))); }); var memberInit = MemberInit(New(typeItem.Type), list); var lambdaEx = Lambda(memberInit, parameterExp); return Call(SelectMethod.MakeGenericMethod(elementType, conversionType), new Expression[2] { source.Expression, lambdaEx }); })));
public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); var typeStore = TypeItem.Get(config.GetType()); var propertyStore = typeStore.PropertyStores.First(x => x.Name == "Services"); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); }
public string[] Where <TColumn>(Expression <Func <TEntity, TColumn> > lamda) { if (lamda is null) { throw new ArgumentNullException(nameof(lamda)); } var parameter = lamda.Parameters[0]; var body = lamda.Body; switch (body.NodeType) { case ExpressionType.Constant when body is ConstantExpression constant: switch (constant.Value) { case string text: return(text.Split(',', ' ')); case string[] arr: return(arr); default: throw new NotImplementedException(); } case ExpressionType.MemberAccess when body is MemberExpression member: return(new string[] { member.Member.Name }); case ExpressionType.MemberInit when body is MemberInitExpression memberInit: return(memberInit.Bindings.Select(x => x.Member.Name).ToArray()); case ExpressionType.New when body is NewExpression newExpression: return(newExpression.Members.Select(x => x.Name).ToArray()); case ExpressionType.Parameter: var storeItem = TypeItem.Get(parameter.Type); return(storeItem.PropertyStores .Where(x => x.CanRead) .Select(x => x.Name) .ToArray()); default: throw new NotSupportedException($"不支持表达式({lamda})!"); } }
/// <summary> /// 获取枚举描述。 /// </summary> /// <typeparam name="TEnum">枚举类型。</typeparam> /// <param name="enum">枚举值。</param> /// <exception cref="ArgumentException">参数不是枚举类型。</exception> /// <returns></returns> public static string GetText <TEnum>(this TEnum @enum) where TEnum : struct { var type = typeof(TEnum); if (!type.IsEnum) { throw new ArgumentException("参数类型不是枚举!"); } var typeStore = TypeItem.Get <TEnum>(); string enumStr = @enum.ToString(); if (typeStore.IsDefined <FlagsAttribute>()) { var values = enumStr.Split(',').Select(x => x.Trim()); if (!values.All(x => typeStore.FieldStores.Any(y => string.Equals(y.Name, x, StringComparison.InvariantCultureIgnoreCase)))) { return("N/A"); } return(string.Join("|", typeStore.FieldStores .Where(x => values.Any(y => string.Equals(y, x.Name, StringComparison.InvariantCultureIgnoreCase))) .Select(x => { var desc2 = x.GetCustomAttribute <DescriptionAttribute>(); return desc2 is null ? x.Name : desc2.Description; }))); } var field = typeStore.FieldStores.FirstOrDefault(x => x.Name == enumStr); if (field is null) { return("N/A"); } var desc = field.GetCustomAttribute <DescriptionAttribute>(); return(desc is null ? field.Name : desc.Description); }
/// <summary> /// 静态构造函数。 /// </summary> static AdapterFormatter() { var contextType = typeof(T); var typeStore = TypeItem.Get(contextType); var matchType = typeof(Match); var groupType = typeof(Group); var contextExp = Parameter(contextType, "context"); var parameterExp = Parameter(matchType, "item"); var getGroupMethod = GetMethodInfo(GetGroup); var checkGroupMethod = GetMethodInfo(CheckGroup); typeStore.MethodStores .Where(x => x.IsPublic && !x.IsStatic && x.Member.DeclaringType == contextType && x.Member.ReturnType == typeof(string) && x.ParameterStores.Count > 0) .OrderByDescending(x => x.ParameterStores.Count) .ForEach(x => { if (!x.ParameterStores.All(y => y.ParameterType == matchType || y.ParameterType == groupType || y.ParameterType == typeof(string) || y.ParameterType == typeof(bool))) { throw new NotSupportedException("仅支持类型System.Text.RegularExpressions.Match、System.Text.RegularExpressions.Group、System.String、System.Boolean类型的映射。"); } var conditions = new List <Expression>(); var variables = new List <ParameterExpression>(); var arguments = new List <Expression>(); var expressions = new List <Expression>(); x.ParameterStores.ForEach(y => { if (y.ParameterType == matchType) { arguments.Add(parameterExp); } else { var groupExp = Variable(groupType, y.Name); variables.Add(groupExp); expressions.Add(Assign(groupExp, Call(null, getGroupMethod, parameterExp, Constant(y.Name)))); if (y.ParameterType == groupType) { conditions.Add(Property(groupExp, "Success")); arguments.Add(groupExp); } else { if (y.ParameterType == typeof(bool)) { arguments.Add(Property(groupExp, "Success")); } else { arguments.Add(Property(groupExp, "Value")); conditions.Add(Call(null, checkGroupMethod, groupExp)); } } } }); var adapter = new Adapter(); var enumerator = conditions.GetEnumerator(); if (enumerator.MoveNext()) { var condition = enumerator.Current; while (enumerator.MoveNext()) { condition = AndAlso(condition, enumerator.Current); } var invoke = Lambda <Func <Match, bool> >(Block(variables, expressions.Concat(new Expression[1] { condition })), parameterExp); adapter.CanConvert = invoke.Compile(); } expressions.Add(Call(contextExp, x.Member, arguments)); var lamdaExp = Lambda <Func <T, Match, string> >(Block(variables, expressions), contextExp, parameterExp); adapter.Convert = lamdaExp.Compile(); AdapterCache.Add(adapter); }); }
/// <inheritdoc /> protected override void VisitCore(MethodCallExpression node) { string name = node.Method.Name; if (isNoPackage) { switch (name) { case MethodCall.TimeOut: case MethodCall.From: case MethodCall.Any: case MethodCall.All: case MethodCall.Contains: case MethodCall.Union: case MethodCall.Concat: case MethodCall.Except: case MethodCall.Intersect: break; default: isNoPackage = false; break; } } switch (name) { case MethodCall.ElementAt: case MethodCall.ElementAtOrDefault: base.Visit(node.Arguments[0]); int index = (int)node.Arguments[1].GetValueFromExpression(); if (index < 0) { throw new IndexOutOfRangeException(); } if (this.take > 0 && index < this.take) { throw new IndexOutOfRangeException(); } this.take = 1; this.skip += index; break; case MethodCall.Take: case MethodCall.TakeLast: if (useAggregation) { throw new DSyntaxErrorException($"使用聚合函数时,禁止使用分页函数({name})!"); } if (name == MethodCall.TakeLast) { reverseOrder ^= true; } int take = (int)node.Arguments[1].GetValueFromExpression(); if (take < 1) { throw new ArgumentOutOfRangeException($"使用{name}函数,参数值必须大于零!"); } if (this.take > 0 && take < this.take) { throw new IndexOutOfRangeException(); } if (this.skip > -1) { if (this.skip > take) { throw new IndexOutOfRangeException(); } take -= this.skip; } if (this.take == -1) { this.take = take; } base.Visit(node.Arguments[0]); if (!useOrderBy && name == MethodCall.TakeLast) { throw new DSyntaxErrorException($"使用函数({name})时,必须使用排序函数(OrderBy/OrderByDescending)!"); } break; case MethodCall.First: case MethodCall.FirstOrDefault: case MethodCall.Single: case MethodCall.SingleOrDefault: // TOP(1) this.take = 1; if (node.Arguments.Count > 1) { VisitCondition(node); } else { Visit(node.Arguments[0]); } break; case MethodCall.Last: case MethodCall.LastOrDefault: // TOP(..) this.take = 1; reverseOrder ^= true; if (node.Arguments.Count > 1) { VisitCondition(node); } else { base.Visit(node.Arguments[0]); } if (!useOrderBy) { throw new DSyntaxErrorException($"使用函数({name})时,必须使用排序函数(OrderBy/OrderByDescending)!"); } break; case MethodCall.Max: buildSelect = false; buildedSelect = true; useAggregation = true; using (var visitor = new MaxVisitor(this)) { visitor.Startup(node); } break; case MethodCall.Min: buildSelect = false; buildedSelect = true; useAggregation = true; using (var visitor = new MinVisitor(this)) { visitor.Startup(node); } break; case MethodCall.Sum: buildSelect = false; buildedSelect = true; useAggregation = true; using (var visitor = new SumVisitor(this)) { visitor.Startup(node); } break; case MethodCall.Average: buildSelect = false; buildedSelect = true; useAggregation = true; using (var visitor = new AverageVisitor(this)) { visitor.Startup(node); } break; case MethodCall.Count: case MethodCall.LongCount: useCount = true; buildSelect = false; buildedSelect = true; useAggregation = true; using (var visitor = new CountVisitor(this)) { visitor.Startup(node); } break; case MethodCall.Skip: case MethodCall.SkipLast: if (useAggregation) { throw new DSyntaxErrorException($"使用聚合函数时,禁止使用分页函数({name})!"); } if (name == MethodCall.SkipLast) { reverseOrder ^= true; } int skip = (int)node.Arguments[1].GetValueFromExpression(); if (skip < 0) { throw new ArgumentOutOfRangeException($"使用({name})函数,参数值不能小于零!"); } if (this.skip == -1) { this.skip = skip; } else { this.skip += skip; } base.Visit(node.Arguments[0]); if (!useOrderBy && name == MethodCall.SkipLast) { throw new DSyntaxErrorException($"使用函数({name})时,必须使用排序函数(OrderBy/OrderByDescending)!"); } break; case MethodCall.Reverse: reverseOrder ^= true; base.Visit(node.Arguments[0]); if (!useOrderBy) { throw new DSyntaxErrorException($"使用函数“{name}”时,必须使用排序函数(OrderBy/OrderByDescending)!"); } break; case MethodCall.GroupBy: case MethodCall.Where when node.Arguments[0].Type.IsGroupingQueryable(): case MethodCall.TakeWhile when node.Arguments[0].Type.IsGroupingQueryable(): case MethodCall.SkipWhile when node.Arguments[0].Type.IsGroupingQueryable(): if (name == MethodCall.GroupBy) { castCache.Add(node.Type.GetGenericArguments().First(), TypeToEntryType(node.Arguments[0].Type)); } if (!useGroupBy) { byVisitor = new GroupByVisitor(this, defaultCache, groupByExpressions); } useGroupBy = true; byVisitor.Startup(node); break; case MethodCall.Select: if (useCount) { base.Visit(node.Arguments[0]); break; } if (!buildSelect) { throw new DSyntaxErrorException($"请将函数“{name}”置于查询最后一个包含入参的函数之后!"); } buildSelect = buildFrom = false; writer.Select(); Workflow(() => { buildedSelect = true; if (isDistinct) { writer.Distinct(); } inSelect = true; Visit(node.Arguments[1]); inSelect = false; writer.From(); if (!hasJoin && !hasCombination) { WriteTableName(node.Arguments[0].Type); } }, () => base.Visit(node.Arguments[0])); break; case MethodCall.SelectMany when node.Arguments.Count == 3: hasJoin = true; var parameterExp = Join(node.Arguments[2], true); bool DoneLeftJoin(ParameterExpression parameter, Expression expression) { if (expression.NodeType == ExpressionType.MemberAccess) { return(false); } switch (expression) { case UnaryExpression unary: return(DoneLeftJoin(parameter, unary.Operand)); case LambdaExpression lambda when lambda.Parameters.Count == 1: return(DoneLeftJoin(parameter, lambda.Body)); case MethodCallExpression methodCall when methodCall.Method.Name == MethodCall.DefaultIfEmpty: if (methodCall.Arguments.Count > 1) { defaultCache.Add(Tuple.Create(parameter.Type, parameter.Name), methodCall.Arguments[1]); } return(true); default: throw new DSyntaxErrorException(); } } using (var visitor = new GroupJoinVisitor(this, parameterExp, DoneLeftJoin(parameterExp, node.Arguments[1]))) { visitor.Startup(node.Arguments[0]); } buildTable = false; break; case MethodCall.Distinct: if (buildedSelect) { throw new DSyntaxErrorException($"函数“{name}”未生效!"); } isDistinct = true; base.Visit(node.Arguments[0]); break; case MethodCall.Cast: case MethodCall.OfType: Type type = node.Type .GetGenericArguments() .First(); if (type.IsValueType || type == typeof(string) || typeof(IEnumerable).IsAssignableFrom(type)) { throw new TypeAccessInvalidException($"“{node.Method.Name}”函数泛型参数类型不能是值类型、字符串类型或迭代类型!"); } var objExp = node.Arguments[0]; var originalType = objExp.Type; if (node.Type == originalType) { base.Visit(objExp); break; } useCast = true; if (!castCache.ContainsKey(type)) { castCache.Add(type, TypeToEntryType(originalType)); } var entry = TypeItem.Get(type); if (memberFilters.Count == 0) { memberFilters.AddRange(entry.PropertyStores .Where(x => x.CanRead && x.CanWrite) .Select(x => x.Name.ToLower())); } else //? 取交集 { memberFilters = memberFilters .Intersect(entry.PropertyStores .Where(x => x.CanRead && x.CanWrite) .Select(x => x.Name.ToLower())) .ToList(); } if (memberFilters.Count == 0) { throw new DException("未指定查询字段!"); } base.Visit(objExp); break; case MethodCall.OrderBy: case MethodCall.ThenBy: case MethodCall.OrderByDescending: case MethodCall.ThenByDescending: useOrderBy = true; if (useAggregation) { base.Visit(node.Arguments[0]); break; } bool thatReverseOrder = reverseOrder; Workflow(() => writer.UsingSort(() => { orderBySwitch.OrderBy(); base.Visit(node.Arguments[1]); if (thatReverseOrder ^ node.Method.Name.EndsWith("Descending")) { writer.Descending(); } }), () => base.Visit(node.Arguments[0])); break; case MethodCall.Join: hasJoin = true; Join(node.Arguments[2], false); Join(node.Arguments[3], true); using (var visitor = new JoinVisitor(this)) { visitor.Startup(node); } buildTable = false; break; case MethodCall.Any: isExists = true; using (var visitor = new AnyVisitor(this)) { visitor.Startup(node); } break; case MethodCall.All: isExists = true; using (var visitor = new AllVisitor(this)) { visitor.Startup(node); } break; case MethodCall.Union: case MethodCall.Concat: case MethodCall.Except: case MethodCall.Intersect: buildTable = buildFrom = false; hasCombination = true; if (isNoPackage) { buildSelect = false; buildedSelect = true; using (var visitor = new CombinationVisitor(this)) { visitor.Startup(node); } break; } string prefix = "x"; if (buildSelect) { buildSelect = false; var tableInfo = MakeTableInfo(node.Arguments[0].Type); Workflow(() => { buildedSelect = true; writer.Select(); if (isDistinct) { writer.Distinct(); } WriteMembers(prefix, FilterMembers(tableInfo.ReadOrWrites)); }, Done); break; } Done(); break; void Done() { writer.From(); writer.OpenBrace(); using (var visitor = new CombinationVisitor(this)) { visitor.Startup(node); } writer.CloseBrace(); writer.WhiteSpace(); writer.Name(prefix = GetEntryAlias(node.Arguments[0].Type, "x")); } default: base.VisitCore(node); break; } ParameterExpression Join(Expression expression, bool isJoin) { switch (expression) { case UnaryExpression unary: return(Join(unary.Operand, isJoin)); case LambdaExpression lambda when lambda.Parameters.Count == 1 || lambda.Parameters.Count == 2: #if NETSTANDARD2_1_OR_GREATER var parameter = lambda.Parameters[^ 1];