diff --git a/Infrastructure/AutoMapperExt.cs b/Infrastructure/AutoMapperExt.cs new file mode 100644 index 00000000..7a1f4b22 --- /dev/null +++ b/Infrastructure/AutoMapperExt.cs @@ -0,0 +1,27 @@ +// *********************************************************************** +// Assembly : FairUtility +// Author : Yubao Li +// Created : 08-27-2015 +// +// Last Modified By : Yubao Li +// Last Modified On : 08-27-2015 +// *********************************************************************** +// +// Copyright (c) . All rights reserved. +// +// +// *********************************************************************** + +using AutoMapper; + +namespace Infrastructure +{ + public class AutoMapperExt + { + public static TResult ConvertTo(T source) + { + var mapper = Mapper.CreateMap(); + return Mapper.Map(source); + } + } +} diff --git a/Infrastructure/ControlHelper.cs b/Infrastructure/ControlHelper.cs new file mode 100644 index 00000000..d7d20d72 --- /dev/null +++ b/Infrastructure/ControlHelper.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; + +namespace Infrastructure +{ + public class ControlHelper + { + /// + /// 根据集合得到下拉框 + /// + /// 实体对象 + /// 实体集合 + /// 下拉框的id + /// 值 字段名 + /// 文本 字段名 + /// 需要选中的值 + /// 样式名称 + /// + public static string GetDropDownByList(List rList, string id, string valFiled, string nameFiled, string selected = "0", string css = "") + { + string str = " "; + return str; + } + + /// + /// 根据枚举得到下拉框 + /// + /// 枚举对象 + /// 下拉框的id + /// 需要选中的值 + /// 样式名称 + /// + public static string GetDropDownByEnum(Type type, string id, string selected = "", string css = "") + { + string str = " "; + return str; + } + } +} diff --git a/Infrastructure/Helper/CookieHelper.cs b/Infrastructure/CookieHelper.cs similarity index 100% rename from Infrastructure/Helper/CookieHelper.cs rename to Infrastructure/CookieHelper.cs diff --git a/Infrastructure/DynamicLinq.cs b/Infrastructure/DynamicLinq.cs new file mode 100644 index 00000000..cb04c9fe --- /dev/null +++ b/Infrastructure/DynamicLinq.cs @@ -0,0 +1,162 @@ +// *********************************************************************** +// Assembly : FairUtility +// Author : Yubao Li +// Created : 08-18-2015 +// +// Last Modified By : Yubao Li +// Last Modified On : 08-18-2015 +// *********************************************************************** +// +// Copyright (c) . All rights reserved. +// +// 动态linq +// *********************************************************************** + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace Infrastructure +{ + public static class DynamicLinq + { + public static ParameterExpression CreateLambdaParam(string name) + { + return Expression.Parameter(typeof(T), name); + } + + /// + /// 创建linq表达示的body部分 + /// + public static Expression GenerateBody(this ParameterExpression param, Filter filterObj) + { + PropertyInfo property = typeof(T).GetProperty(filterObj.Key); + + //组装左边 + Expression left = Expression.Property(param, property); + //组装右边 + Expression right = null; + + if (property.PropertyType == typeof(int)) + { + right = Expression.Constant(int.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(DateTime)) + { + right = Expression.Constant(DateTime.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(string)) + { + right = Expression.Constant((filterObj.Value)); + } + else if (property.PropertyType == typeof(decimal)) + { + right = Expression.Constant(decimal.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(Guid)) + { + right = Expression.Constant(Guid.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(bool)) + { + right = Expression.Constant(filterObj.Value.Equals("1")); + } + else + { + throw new Exception("暂不能解析该Key的类型"); + } + + //c.XXX=="XXX" + Expression filter = Expression.Equal(left, right); + switch (filterObj.Contrast) + { + case "<=": + filter = Expression.LessThanOrEqual(left, right); + break; + + case "<": + filter = Expression.LessThan(left, right); + break; + + case ">": + filter = Expression.GreaterThan(left, right); + break; + + case ">=": + filter = Expression.GreaterThanOrEqual(left, right); + break; + + case "like": + filter = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), + Expression.Constant(filterObj.Value)); + break; + } + + return filter; + } + + public static Expression> GenerateTypeBody(this ParameterExpression param, Filter filterObj) + { + return (Expression>)(param.GenerateBody(filterObj)); + } + + /// + /// 创建完整的lambda + /// + public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body) + { + //c=>c.XXX=="XXX" + return Expression.Lambda(body, param); + } + + public static Expression> GenerateTypeLambda(this ParameterExpression param, Expression body) + { + return (Expression>)(param.GenerateLambda(body)); + } + + public static Expression AndAlso(this Expression expression, Expression expressionRight) + { + return Expression.AndAlso(expression, expressionRight); + } + + public static Expression Or(this Expression expression, Expression expressionRight) + { + return Expression.Or(expression, expressionRight); + } + + public static Expression And(this Expression expression, Expression expressionRight) + { + return Expression.And(expression, expressionRight); + } + + //系统已经有该函数的实现 + //public static IQueryable Where(this IQueryable query, Expression expression) + //{ + // Expression expr = Expression.Call(typeof(Queryable), "Where", new[] { typeof(T) }, + // Expression.Constant(query), expression); + // //生成动态查询 + // IQueryable result = query.Provider.CreateQuery(expr); + // return result; + //} + + public static IQueryable GenerateFilter(this IQueryable query, string filterjson) + { + if (!string.IsNullOrEmpty(filterjson)) + { + var filters = JsonHelper.Instance.Deserialize>(filterjson); + var param = CreateLambdaParam("c"); + + Expression result = Expression.Constant(true); + foreach (var filter in filters) + { + result = result.AndAlso(param.GenerateBody(filter)); + } + + query = query.Where(param.GenerateTypeLambda(result)); + } + return query; + } + } +} \ No newline at end of file diff --git a/Infrastructure/DynamicQueryable.cs b/Infrastructure/DynamicQueryable.cs new file mode 100644 index 00000000..7b6da375 --- /dev/null +++ b/Infrastructure/DynamicQueryable.cs @@ -0,0 +1,2075 @@ +//Copyright (C) Microsoft Corporation. All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using System.Threading; + +namespace Infrastructure +{ + public static class DynamicQueryable + { + public static IQueryable Where(this IQueryable source, string predicate, params object[] values) { + return (IQueryable)Where((IQueryable)source, predicate, values); + } + + public static IQueryable Where(this IQueryable source, string predicate, params object[] values) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values); + return source.Provider.CreateQuery( + Expression.Call( + typeof(Queryable), "Where", + new Type[] { source.ElementType }, + source.Expression, Expression.Quote(lambda))); + } + + public static IQueryable Select(this IQueryable source, string selector, params object[] values) { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values); + return source.Provider.CreateQuery( + Expression.Call( + typeof(Queryable), "Select", + new Type[] { source.ElementType, lambda.Body.Type }, + source.Expression, Expression.Quote(lambda))); + } + + public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) { + return (IQueryable)OrderBy((IQueryable)source, ordering, values); + } + + public static IQueryable ThenBy(this IQueryable source, string ordering, params object[] values) + { + return (IQueryable)ThenBy((IQueryable)source, ordering, values); + } + + public static IQueryable ThenBy(this IQueryable source, string ordering, params object[] values) + { + if (source == null) throw new ArgumentNullException("source"); + if (ordering == null) throw new ArgumentNullException("ordering"); + ParameterExpression[] parameters = new ParameterExpression[] { + Expression.Parameter(source.ElementType, "") }; + ExpressionParser parser = new ExpressionParser(parameters, ordering, values); + IEnumerable orderings = parser.ParseOrdering(); + Expression queryExpr = source.Expression; + string methodAsc = "ThenBy"; + string methodDesc = "ThenByDescending"; + foreach (DynamicOrdering o in orderings) + { + queryExpr = Expression.Call( + typeof(Queryable), o.Ascending ? methodAsc : methodDesc, + new Type[] { source.ElementType, o.Selector.Type }, + queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters))); + + } + return source.Provider.CreateQuery(queryExpr); + } + + public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) { + if (source == null) throw new ArgumentNullException("source"); + if (ordering == null) throw new ArgumentNullException("ordering"); + ParameterExpression[] parameters = new ParameterExpression[] { + Expression.Parameter(source.ElementType, "") }; + ExpressionParser parser = new ExpressionParser(parameters, ordering, values); + IEnumerable orderings = parser.ParseOrdering(); + Expression queryExpr = source.Expression; + string methodAsc = "OrderBy"; + string methodDesc = "OrderByDescending"; + foreach (DynamicOrdering o in orderings) { + queryExpr = Expression.Call( + typeof(Queryable), o.Ascending ? methodAsc : methodDesc, + new Type[] { source.ElementType, o.Selector.Type }, + queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters))); + methodAsc = "ThenBy"; + methodDesc = "ThenByDescending"; + } + return source.Provider.CreateQuery(queryExpr); + } + + public static IQueryable OrderBy(this IQueryable source, string propertyName, bool ascending) + where T : class + { + Type type = typeof (T); + + PropertyInfo property = type.GetProperty(propertyName); + if (property == null) + throw new ArgumentException("propertyName", "Not Exist"); + + ParameterExpression param = Expression.Parameter(type, "p"); + Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property); + LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param); + + string methodName = ascending ? "OrderBy" : "OrderByDescending"; + + MethodCallExpression resultExp = Expression.Call(typeof (Queryable), methodName, + new Type[] {type, property.PropertyType}, source.Expression, Expression.Quote(orderByExpression)); + + return source.Provider.CreateQuery(resultExp); + } + + public static IQueryable Take(this IQueryable source, int count) { + if (source == null) throw new ArgumentNullException("source"); + return source.Provider.CreateQuery( + Expression.Call( + typeof(Queryable), "Take", + new Type[] { source.ElementType }, + source.Expression, Expression.Constant(count))); + } + + public static IQueryable Skip(this IQueryable source, int count) { + if (source == null) throw new ArgumentNullException("source"); + return source.Provider.CreateQuery( + Expression.Call( + typeof(Queryable), "Skip", + new Type[] { source.ElementType }, + source.Expression, Expression.Constant(count))); + } + + public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values) { + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + if (elementSelector == null) throw new ArgumentNullException("elementSelector"); + LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values); + LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values); + return source.Provider.CreateQuery( + Expression.Call( + typeof(Queryable), "GroupBy", + new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type }, + source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda))); + } + + public static bool Any(this IQueryable source) { + if (source == null) throw new ArgumentNullException("source"); + return (bool)source.Provider.Execute( + Expression.Call( + typeof(Queryable), "Any", + new Type[] { source.ElementType }, source.Expression)); + } + + public static int Count(this IQueryable source) { + if (source == null) throw new ArgumentNullException("source"); + return (int)source.Provider.Execute( + Expression.Call( + typeof(Queryable), "Count", + new Type[] { source.ElementType }, source.Expression)); + } + } + + public abstract class DynamicClass + { + public override string ToString() { + PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < props.Length; i++) { + if (i > 0) sb.Append(", "); + sb.Append(props[i].Name); + sb.Append("="); + sb.Append(props[i].GetValue(this, null)); + } + sb.Append("}"); + return sb.ToString(); + } + } + + public class DynamicProperty + { + string name; + Type type; + + public DynamicProperty(string name, Type type) { + if (name == null) throw new ArgumentNullException("name"); + if (type == null) throw new ArgumentNullException("type"); + this.name = name; + this.type = type; + } + + public string Name { + get { return name; } + } + + public Type Type { + get { return type; } + } + } + + public static class DynamicExpression + { + public static Expression Parse(Type resultType, string expression, params object[] values) { + ExpressionParser parser = new ExpressionParser(null, expression, values); + return parser.Parse(resultType); + } + + public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values) { + return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, values); + } + + public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values) { + ExpressionParser parser = new ExpressionParser(parameters, expression, values); + return Expression.Lambda(parser.Parse(resultType), parameters); + } + + public static Expression> ParseLambda(string expression, params object[] values) { + return (Expression>)ParseLambda(typeof(T), typeof(S), expression, values); + } + + public static Type CreateClass(params DynamicProperty[] properties) { + return ClassFactory.Instance.GetDynamicClass(properties); + } + + public static Type CreateClass(IEnumerable properties) { + return ClassFactory.Instance.GetDynamicClass(properties); + } + } + + internal class DynamicOrdering + { + public Expression Selector; + public bool Ascending; + } + + internal class Signature : IEquatable + { + public DynamicProperty[] properties; + public int hashCode; + + public Signature(IEnumerable properties) { + this.properties = properties.ToArray(); + hashCode = 0; + foreach (DynamicProperty p in properties) { + hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode(); + } + } + + public override int GetHashCode() { + return hashCode; + } + + public override bool Equals(object obj) { + return obj is Signature ? Equals((Signature)obj) : false; + } + + public bool Equals(Signature other) { + if (properties.Length != other.properties.Length) return false; + for (int i = 0; i < properties.Length; i++) { + if (properties[i].Name != other.properties[i].Name || + properties[i].Type != other.properties[i].Type) return false; + } + return true; + } + } + + internal class ClassFactory + { + public static readonly ClassFactory Instance = new ClassFactory(); + + static ClassFactory() { } // Trigger lazy initialization of static fields + + ModuleBuilder module; + Dictionary classes; + int classCount; + ReaderWriterLock rwLock; + + private ClassFactory() { + AssemblyName name = new AssemblyName("DynamicClasses"); + AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); +#if ENABLE_LINQ_PARTIAL_TRUST + new ReflectionPermission(PermissionState.Unrestricted).Assert(); +#endif + try { + module = assembly.DefineDynamicModule("Module"); + } + finally { +#if ENABLE_LINQ_PARTIAL_TRUST + PermissionSet.RevertAssert(); +#endif + } + classes = new Dictionary(); + rwLock = new ReaderWriterLock(); + } + + public Type GetDynamicClass(IEnumerable properties) { + rwLock.AcquireReaderLock(Timeout.Infinite); + try { + Signature signature = new Signature(properties); + Type type; + if (!classes.TryGetValue(signature, out type)) { + type = CreateDynamicClass(signature.properties); + classes.Add(signature, type); + } + return type; + } + finally { + rwLock.ReleaseReaderLock(); + } + } + + Type CreateDynamicClass(DynamicProperty[] properties) { + LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite); + try { + string typeName = "DynamicClass" + (classCount + 1); +#if ENABLE_LINQ_PARTIAL_TRUST + new ReflectionPermission(PermissionState.Unrestricted).Assert(); +#endif + try { + TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class | + TypeAttributes.Public, typeof(DynamicClass)); + FieldInfo[] fields = GenerateProperties(tb, properties); + GenerateEquals(tb, fields); + GenerateGetHashCode(tb, fields); + Type result = tb.CreateType(); + classCount++; + return result; + } + finally { +#if ENABLE_LINQ_PARTIAL_TRUST + PermissionSet.RevertAssert(); +#endif + } + } + finally { + rwLock.DowngradeFromWriterLock(ref cookie); + } + } + + FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties) { + FieldInfo[] fields = new FieldBuilder[properties.Length]; + for (int i = 0; i < properties.Length; i++) { + DynamicProperty dp = properties[i]; + FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private); + PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null); + MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name, + MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, + dp.Type, Type.EmptyTypes); + ILGenerator genGet = mbGet.GetILGenerator(); + genGet.Emit(OpCodes.Ldarg_0); + genGet.Emit(OpCodes.Ldfld, fb); + genGet.Emit(OpCodes.Ret); + MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name, + MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, + null, new Type[] { dp.Type }); + ILGenerator genSet = mbSet.GetILGenerator(); + genSet.Emit(OpCodes.Ldarg_0); + genSet.Emit(OpCodes.Ldarg_1); + genSet.Emit(OpCodes.Stfld, fb); + genSet.Emit(OpCodes.Ret); + pb.SetGetMethod(mbGet); + pb.SetSetMethod(mbSet); + fields[i] = fb; + } + return fields; + } + + void GenerateEquals(TypeBuilder tb, FieldInfo[] fields) { + MethodBuilder mb = tb.DefineMethod("Equals", + MethodAttributes.Public | MethodAttributes.ReuseSlot | + MethodAttributes.Virtual | MethodAttributes.HideBySig, + typeof(bool), new Type[] { typeof(object) }); + ILGenerator gen = mb.GetILGenerator(); + LocalBuilder other = gen.DeclareLocal(tb); + Label next = gen.DefineLabel(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Isinst, tb); + gen.Emit(OpCodes.Stloc, other); + gen.Emit(OpCodes.Ldloc, other); + gen.Emit(OpCodes.Brtrue_S, next); + gen.Emit(OpCodes.Ldc_I4_0); + gen.Emit(OpCodes.Ret); + gen.MarkLabel(next); + foreach (FieldInfo field in fields) { + Type ft = field.FieldType; + Type ct = typeof(EqualityComparer<>).MakeGenericType(ft); + next = gen.DefineLabel(); + gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldfld, field); + gen.Emit(OpCodes.Ldloc, other); + gen.Emit(OpCodes.Ldfld, field); + gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null); + gen.Emit(OpCodes.Brtrue_S, next); + gen.Emit(OpCodes.Ldc_I4_0); + gen.Emit(OpCodes.Ret); + gen.MarkLabel(next); + } + gen.Emit(OpCodes.Ldc_I4_1); + gen.Emit(OpCodes.Ret); + } + + void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields) { + MethodBuilder mb = tb.DefineMethod("GetHashCode", + MethodAttributes.Public | MethodAttributes.ReuseSlot | + MethodAttributes.Virtual | MethodAttributes.HideBySig, + typeof(int), Type.EmptyTypes); + ILGenerator gen = mb.GetILGenerator(); + gen.Emit(OpCodes.Ldc_I4_0); + foreach (FieldInfo field in fields) { + Type ft = field.FieldType; + Type ct = typeof(EqualityComparer<>).MakeGenericType(ft); + gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldfld, field); + gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null); + gen.Emit(OpCodes.Xor); + } + gen.Emit(OpCodes.Ret); + } + } + + public sealed class ParseException : Exception + { + int position; + + public ParseException(string message, int position) + : base(message) { + this.position = position; + } + + public int Position { + get { return position; } + } + + public override string ToString() { + return string.Format(Res.ParseExceptionFormat, Message, position); + } + } + + internal class ExpressionParser + { + struct Token + { + public TokenId id; + public string text; + public int pos; + } + + enum TokenId + { + Unknown, + End, + Identifier, + StringLiteral, + IntegerLiteral, + RealLiteral, + Exclamation, + Percent, + Amphersand, + OpenParen, + CloseParen, + Asterisk, + Plus, + Comma, + Minus, + Dot, + Slash, + Colon, + LessThan, + Equal, + GreaterThan, + Question, + OpenBracket, + CloseBracket, + Bar, + ExclamationEqual, + DoubleAmphersand, + LessThanEqual, + LessGreater, + DoubleEqual, + GreaterThanEqual, + DoubleBar + } + + interface ILogicalSignatures + { + void F(bool x, bool y); + void F(bool? x, bool? y); + } + + interface IArithmeticSignatures + { + void F(int x, int y); + void F(uint x, uint y); + void F(long x, long y); + void F(ulong x, ulong y); + void F(float x, float y); + void F(double x, double y); + void F(decimal x, decimal y); + void F(int? x, int? y); + void F(uint? x, uint? y); + void F(long? x, long? y); + void F(ulong? x, ulong? y); + void F(float? x, float? y); + void F(double? x, double? y); + void F(decimal? x, decimal? y); + } + + interface IRelationalSignatures : IArithmeticSignatures + { + void F(string x, string y); + void F(char x, char y); + void F(DateTime x, DateTime y); + void F(TimeSpan x, TimeSpan y); + void F(char? x, char? y); + void F(DateTime? x, DateTime? y); + void F(TimeSpan? x, TimeSpan? y); + } + + interface IEqualitySignatures : IRelationalSignatures + { + void F(bool x, bool y); + void F(bool? x, bool? y); + } + + interface IAddSignatures : IArithmeticSignatures + { + void F(DateTime x, TimeSpan y); + void F(TimeSpan x, TimeSpan y); + void F(DateTime? x, TimeSpan? y); + void F(TimeSpan? x, TimeSpan? y); + } + + interface ISubtractSignatures : IAddSignatures + { + void F(DateTime x, DateTime y); + void F(DateTime? x, DateTime? y); + } + + interface INegationSignatures + { + void F(int x); + void F(long x); + void F(float x); + void F(double x); + void F(decimal x); + void F(int? x); + void F(long? x); + void F(float? x); + void F(double? x); + void F(decimal? x); + } + + interface INotSignatures + { + void F(bool x); + void F(bool? x); + } + + interface IEnumerableSignatures + { + void Where(bool predicate); + void Any(); + void Any(bool predicate); + void All(bool predicate); + void Count(); + void Count(bool predicate); + void Min(object selector); + void Max(object selector); + void Sum(int selector); + void Sum(int? selector); + void Sum(long selector); + void Sum(long? selector); + void Sum(float selector); + void Sum(float? selector); + void Sum(double selector); + void Sum(double? selector); + void Sum(decimal selector); + void Sum(decimal? selector); + void Average(int selector); + void Average(int? selector); + void Average(long selector); + void Average(long? selector); + void Average(float selector); + void Average(float? selector); + void Average(double selector); + void Average(double? selector); + void Average(decimal selector); + void Average(decimal? selector); + } + + static readonly Type[] predefinedTypes = { + typeof(Object), + typeof(Boolean), + typeof(Char), + typeof(String), + typeof(SByte), + typeof(Byte), + typeof(Int16), + typeof(UInt16), + typeof(Int32), + typeof(UInt32), + typeof(Int64), + typeof(UInt64), + typeof(Single), + typeof(Double), + typeof(Decimal), + typeof(DateTime), + typeof(TimeSpan), + typeof(Guid), + typeof(Math), + typeof(Convert) + }; + + static readonly Expression trueLiteral = Expression.Constant(true); + static readonly Expression falseLiteral = Expression.Constant(false); + static readonly Expression nullLiteral = Expression.Constant(null); + + static readonly string keywordIt = "it"; + static readonly string keywordIif = "iif"; + static readonly string keywordNew = "new"; + + static Dictionary keywords; + + Dictionary symbols; + IDictionary externals; + Dictionary literals; + ParameterExpression it; + string text; + int textPos; + int textLen; + char ch; + Token token; + + public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values) { + if (expression == null) throw new ArgumentNullException("expression"); + if (keywords == null) keywords = CreateKeywords(); + symbols = new Dictionary(StringComparer.OrdinalIgnoreCase); + literals = new Dictionary(); + if (parameters != null) ProcessParameters(parameters); + if (values != null) ProcessValues(values); + text = expression; + textLen = text.Length; + SetTextPos(0); + NextToken(); + } + + void ProcessParameters(ParameterExpression[] parameters) { + foreach (ParameterExpression pe in parameters) + if (!String.IsNullOrEmpty(pe.Name)) + AddSymbol(pe.Name, pe); + if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name)) + it = parameters[0]; + } + + void ProcessValues(object[] values) { + for (int i = 0; i < values.Length; i++) { + object value = values[i]; + if (i == values.Length - 1 && value is IDictionary) { + externals = (IDictionary)value; + } + else { + AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value); + } + } + } + + void AddSymbol(string name, object value) { + if (symbols.ContainsKey(name)) + throw ParseError(Res.DuplicateIdentifier, name); + symbols.Add(name, value); + } + + public Expression Parse(Type resultType) { + int exprPos = token.pos; + Expression expr = ParseExpression(); + if (resultType != null) + if ((expr = PromoteExpression(expr, resultType, true)) == null) + throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType)); + ValidateToken(TokenId.End, Res.SyntaxError); + return expr; + } + +#pragma warning disable 0219 + public IEnumerable ParseOrdering() { + List orderings = new List(); + while (true) { + Expression expr = ParseExpression(); + bool ascending = true; + if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) { + NextToken(); + } + else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) { + NextToken(); + ascending = false; + } + orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending }); + if (token.id != TokenId.Comma) break; + NextToken(); + } + ValidateToken(TokenId.End, Res.SyntaxError); + return orderings; + } +#pragma warning restore 0219 + + // ?: operator + Expression ParseExpression() { + int errorPos = token.pos; + Expression expr = ParseLogicalOr(); + if (token.id == TokenId.Question) { + NextToken(); + Expression expr1 = ParseExpression(); + ValidateToken(TokenId.Colon, Res.ColonExpected); + NextToken(); + Expression expr2 = ParseExpression(); + expr = GenerateConditional(expr, expr1, expr2, errorPos); + } + return expr; + } + + // ||, or operator + Expression ParseLogicalOr() { + Expression left = ParseLogicalAnd(); + while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or")) { + Token op = token; + NextToken(); + Expression right = ParseLogicalAnd(); + CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos); + left = Expression.OrElse(left, right); + } + return left; + } + + // &&, and operator + Expression ParseLogicalAnd() { + Expression left = ParseComparison(); + while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and")) { + Token op = token; + NextToken(); + Expression right = ParseComparison(); + CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos); + left = Expression.AndAlso(left, right); + } + return left; + } + + // =, ==, !=, <>, >, >=, <, <= operators + Expression ParseComparison() { + Expression left = ParseAdditive(); + while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual || + token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater || + token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual || + token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual) { + Token op = token; + NextToken(); + Expression right = ParseAdditive(); + bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual || + op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater; + if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType) { + if (left.Type != right.Type) { + if (left.Type.IsAssignableFrom(right.Type)) { + right = Expression.Convert(right, left.Type); + } + else if (right.Type.IsAssignableFrom(left.Type)) { + left = Expression.Convert(left, right.Type); + } + else { + throw IncompatibleOperandsError(op.text, left, right, op.pos); + } + } + } + else if (IsEnumType(left.Type) || IsEnumType(right.Type)) { + if (left.Type != right.Type) { + Expression e; + if ((e = PromoteExpression(right, left.Type, true)) != null) { + right = e; + } + else if ((e = PromoteExpression(left, right.Type, true)) != null) { + left = e; + } + else { + throw IncompatibleOperandsError(op.text, left, right, op.pos); + } + } + } + else { + CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), + op.text, ref left, ref right, op.pos); + } + switch (op.id) { + case TokenId.Equal: + case TokenId.DoubleEqual: + left = GenerateEqual(left, right); + break; + case TokenId.ExclamationEqual: + case TokenId.LessGreater: + left = GenerateNotEqual(left, right); + break; + case TokenId.GreaterThan: + left = GenerateGreaterThan(left, right); + break; + case TokenId.GreaterThanEqual: + left = GenerateGreaterThanEqual(left, right); + break; + case TokenId.LessThan: + left = GenerateLessThan(left, right); + break; + case TokenId.LessThanEqual: + left = GenerateLessThanEqual(left, right); + break; + } + } + return left; + } + + // +, -, & operators + Expression ParseAdditive() { + Expression left = ParseMultiplicative(); + while (token.id == TokenId.Plus || token.id == TokenId.Minus || + token.id == TokenId.Amphersand) { + Token op = token; + NextToken(); + Expression right = ParseMultiplicative(); + switch (op.id) { + case TokenId.Plus: + if (left.Type == typeof(string) || right.Type == typeof(string)) + goto case TokenId.Amphersand; + CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos); + left = GenerateAdd(left, right); + break; + case TokenId.Minus: + CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos); + left = GenerateSubtract(left, right); + break; + case TokenId.Amphersand: + left = GenerateStringConcat(left, right); + break; + } + } + return left; + } + + // *, /, %, mod operators + Expression ParseMultiplicative() { + Expression left = ParseUnary(); + while (token.id == TokenId.Asterisk || token.id == TokenId.Slash || + token.id == TokenId.Percent || TokenIdentifierIs("mod")) { + Token op = token; + NextToken(); + Expression right = ParseUnary(); + CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos); + switch (op.id) { + case TokenId.Asterisk: + left = Expression.Multiply(left, right); + break; + case TokenId.Slash: + left = Expression.Divide(left, right); + break; + case TokenId.Percent: + case TokenId.Identifier: + left = Expression.Modulo(left, right); + break; + } + } + return left; + } + + // -, !, not unary operators + Expression ParseUnary() { + if (token.id == TokenId.Minus || token.id == TokenId.Exclamation || + TokenIdentifierIs("not")) { + Token op = token; + NextToken(); + if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral || + token.id == TokenId.RealLiteral)) { + token.text = "-" + token.text; + token.pos = op.pos; + return ParsePrimary(); + } + Expression expr = ParseUnary(); + if (op.id == TokenId.Minus) { + CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos); + expr = Expression.Negate(expr); + } + else { + CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos); + expr = Expression.Not(expr); + } + return expr; + } + return ParsePrimary(); + } + + Expression ParsePrimary() { + Expression expr = ParsePrimaryStart(); + while (true) { + if (token.id == TokenId.Dot) { + NextToken(); + expr = ParseMemberAccess(null, expr); + } + else if (token.id == TokenId.OpenBracket) { + expr = ParseElementAccess(expr); + } + else { + break; + } + } + return expr; + } + + Expression ParsePrimaryStart() { + switch (token.id) { + case TokenId.Identifier: + return ParseIdentifier(); + case TokenId.StringLiteral: + return ParseStringLiteral(); + case TokenId.IntegerLiteral: + return ParseIntegerLiteral(); + case TokenId.RealLiteral: + return ParseRealLiteral(); + case TokenId.OpenParen: + return ParseParenExpression(); + default: + throw ParseError(Res.ExpressionExpected); + } + } + + Expression ParseStringLiteral() { + ValidateToken(TokenId.StringLiteral); + char quote = token.text[0]; + string s = token.text.Substring(1, token.text.Length - 2); + int start = 0; + while (true) { + int i = s.IndexOf(quote, start); + if (i < 0) break; + s = s.Remove(i, 1); + start = i + 1; + } + //if (quote == '\'') { + // if (s.Length != 1) + // throw ParseError(Res.InvalidCharacterLiteral); + // NextToken(); + // return CreateLiteral(s[0], s); + //} + NextToken(); + return CreateLiteral(s, s); + } + + Expression ParseIntegerLiteral() { + ValidateToken(TokenId.IntegerLiteral); + string text = token.text; + if (text[0] != '-') { + ulong value; + if (!UInt64.TryParse(text, out value)) + throw ParseError(Res.InvalidIntegerLiteral, text); + NextToken(); + if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text); + if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text); + if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text); + return CreateLiteral(value, text); + } + else { + long value; + if (!Int64.TryParse(text, out value)) + throw ParseError(Res.InvalidIntegerLiteral, text); + NextToken(); + if (value >= Int32.MinValue && value <= Int32.MaxValue) + return CreateLiteral((int)value, text); + return CreateLiteral(value, text); + } + } + + Expression ParseRealLiteral() { + ValidateToken(TokenId.RealLiteral); + string text = token.text; + object value = null; + char last = text[text.Length - 1]; + if (last == 'F' || last == 'f') { + float f; + if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f; + } + else { + double d; + if (Double.TryParse(text, out d)) value = d; + } + if (value == null) throw ParseError(Res.InvalidRealLiteral, text); + NextToken(); + return CreateLiteral(value, text); + } + + Expression CreateLiteral(object value, string text) { + ConstantExpression expr = Expression.Constant(value); + literals.Add(expr, text); + return expr; + } + + Expression ParseParenExpression() { + ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); + NextToken(); + Expression e = ParseExpression(); + ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected); + NextToken(); + return e; + } + + Expression ParseIdentifier() { + ValidateToken(TokenId.Identifier); + object value; + if (keywords.TryGetValue(token.text, out value)) { + if (value is Type) return ParseTypeAccess((Type)value); + if (value == (object)keywordIt) return ParseIt(); + if (value == (object)keywordIif) return ParseIif(); + if (value == (object)keywordNew) return ParseNew(); + NextToken(); + return (Expression)value; + } + if (symbols.TryGetValue(token.text, out value) || + externals != null && externals.TryGetValue(token.text, out value)) { + Expression expr = value as Expression; + if (expr == null) { + expr = Expression.Constant(value); + } + else { + LambdaExpression lambda = expr as LambdaExpression; + if (lambda != null) return ParseLambdaInvocation(lambda); + } + NextToken(); + return expr; + } + if (it != null) return ParseMemberAccess(null, it); + throw ParseError(Res.UnknownIdentifier, token.text); + } + + Expression ParseIt() { + if (it == null) + throw ParseError(Res.NoItInScope); + NextToken(); + return it; + } + + Expression ParseIif() { + int errorPos = token.pos; + NextToken(); + Expression[] args = ParseArgumentList(); + if (args.Length != 3) + throw ParseError(errorPos, Res.IifRequiresThreeArgs); + return GenerateConditional(args[0], args[1], args[2], errorPos); + } + + Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos) { + if (test.Type != typeof(bool)) + throw ParseError(errorPos, Res.FirstExprMustBeBool); + if (expr1.Type != expr2.Type) { + Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null; + Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null; + if (expr1as2 != null && expr2as1 == null) { + expr1 = expr1as2; + } + else if (expr2as1 != null && expr1as2 == null) { + expr2 = expr2as1; + } + else { + string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null"; + string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null"; + if (expr1as2 != null && expr2as1 != null) + throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2); + throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2); + } + } + return Expression.Condition(test, expr1, expr2); + } + + Expression ParseNew() { + NextToken(); + ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); + NextToken(); + List properties = new List(); + List expressions = new List(); + while (true) { + int exprPos = token.pos; + Expression expr = ParseExpression(); + string propName; + if (TokenIdentifierIs("as")) { + NextToken(); + propName = GetIdentifier(); + NextToken(); + } + else { + MemberExpression me = expr as MemberExpression; + if (me == null) throw ParseError(exprPos, Res.MissingAsClause); + propName = me.Member.Name; + } + expressions.Add(expr); + properties.Add(new DynamicProperty(propName, expr.Type)); + if (token.id != TokenId.Comma) break; + NextToken(); + } + ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); + NextToken(); + Type type = DynamicExpression.CreateClass(properties); + MemberBinding[] bindings = new MemberBinding[properties.Count]; + for (int i = 0; i < bindings.Length; i++) + bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]); + return Expression.MemberInit(Expression.New(type), bindings); + } + + Expression ParseLambdaInvocation(LambdaExpression lambda) { + int errorPos = token.pos; + NextToken(); + Expression[] args = ParseArgumentList(); + MethodBase method; + if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1) + throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda); + return Expression.Invoke(lambda, args); + } + + Expression ParseTypeAccess(Type type) { + int errorPos = token.pos; + NextToken(); + if (token.id == TokenId.Question) { + if (!type.IsValueType || IsNullableType(type)) + throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type)); + type = typeof(Nullable<>).MakeGenericType(type); + NextToken(); + } + if (token.id == TokenId.OpenParen) { + Expression[] args = ParseArgumentList(); + MethodBase method; + switch (FindBestMethod(type.GetConstructors(), args, out method)) { + case 0: + if (args.Length == 1) + return GenerateConversion(args[0], type, errorPos); + throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type)); + case 1: + return Expression.New((ConstructorInfo)method, args); + default: + throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type)); + } + } + ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected); + NextToken(); + return ParseMemberAccess(type, null); + } + + Expression GenerateConversion(Expression expr, Type type, int errorPos) { + Type exprType = expr.Type; + if (exprType == type) return expr; + if (exprType.IsValueType && type.IsValueType) { + if ((IsNullableType(exprType) || IsNullableType(type)) && + GetNonNullableType(exprType) == GetNonNullableType(type)) + return Expression.Convert(expr, type); + if ((IsNumericType(exprType) || IsEnumType(exprType)) && + (IsNumericType(type)) || IsEnumType(type)) + return Expression.ConvertChecked(expr, type); + } + if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) || + exprType.IsInterface || type.IsInterface) + return Expression.Convert(expr, type); + throw ParseError(errorPos, Res.CannotConvertValue, + GetTypeName(exprType), GetTypeName(type)); + } + + Expression ParseMemberAccess(Type type, Expression instance) { + if (instance != null) type = instance.Type; + int errorPos = token.pos; + string id = GetIdentifier(); + NextToken(); + if (token.id == TokenId.OpenParen) { + if (instance != null && type != typeof(string)) { + Type enumerableType = FindGenericType(typeof(IEnumerable<>), type); + if (enumerableType != null) { + Type elementType = enumerableType.GetGenericArguments()[0]; + return ParseAggregate(instance, elementType, id, errorPos); + } + } + Expression[] args = ParseArgumentList(); + MethodBase mb; + switch (FindMethod(type, id, instance == null, args, out mb)) { + case 0: + throw ParseError(errorPos, Res.NoApplicableMethod, + id, GetTypeName(type)); + case 1: + MethodInfo method = (MethodInfo)mb; + if (!IsPredefinedType(method.DeclaringType)) + throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType)); + if (method.ReturnType == typeof(void)) + throw ParseError(errorPos, Res.MethodIsVoid, + id, GetTypeName(method.DeclaringType)); + return Expression.Call(instance, (MethodInfo)method, args); + default: + throw ParseError(errorPos, Res.AmbiguousMethodInvocation, + id, GetTypeName(type)); + } + } + else { + MemberInfo member = FindPropertyOrField(type, id, instance == null); + if (member == null) + throw ParseError(errorPos, Res.UnknownPropertyOrField, + id, GetTypeName(type)); + return member is PropertyInfo ? + Expression.Property(instance, (PropertyInfo)member) : + Expression.Field(instance, (FieldInfo)member); + } + } + + static Type FindGenericType(Type generic, Type type) { + while (type != null && type != typeof(object)) { + if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type; + if (generic.IsInterface) { + foreach (Type intfType in type.GetInterfaces()) { + Type found = FindGenericType(generic, intfType); + if (found != null) return found; + } + } + type = type.BaseType; + } + return null; + } + + Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos) { + ParameterExpression outerIt = it; + ParameterExpression innerIt = Expression.Parameter(elementType, ""); + it = innerIt; + Expression[] args = ParseArgumentList(); + it = outerIt; + MethodBase signature; + if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1) + throw ParseError(errorPos, Res.NoApplicableAggregate, methodName); + Type[] typeArgs; + if (signature.Name == "Min" || signature.Name == "Max") { + typeArgs = new Type[] { elementType, args[0].Type }; + } + else { + typeArgs = new Type[] { elementType }; + } + if (args.Length == 0) { + args = new Expression[] { instance }; + } + else { + args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) }; + } + return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args); + } + + Expression[] ParseArgumentList() { + ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); + NextToken(); + Expression[] args = token.id != TokenId.CloseParen ? ParseArguments() : new Expression[0]; + ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); + NextToken(); + return args; + } + + Expression[] ParseArguments() { + List argList = new List(); + while (true) { + argList.Add(ParseExpression()); + if (token.id != TokenId.Comma) break; + NextToken(); + } + return argList.ToArray(); + } + + Expression ParseElementAccess(Expression expr) { + int errorPos = token.pos; + ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected); + NextToken(); + Expression[] args = ParseArguments(); + ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected); + NextToken(); + if (expr.Type.IsArray) { + if (expr.Type.GetArrayRank() != 1 || args.Length != 1) + throw ParseError(errorPos, Res.CannotIndexMultiDimArray); + Expression index = PromoteExpression(args[0], typeof(int), true); + if (index == null) + throw ParseError(errorPos, Res.InvalidIndex); + return Expression.ArrayIndex(expr, index); + } + else { + MethodBase mb; + switch (FindIndexer(expr.Type, args, out mb)) { + case 0: + throw ParseError(errorPos, Res.NoApplicableIndexer, + GetTypeName(expr.Type)); + case 1: + return Expression.Call(expr, (MethodInfo)mb, args); + default: + throw ParseError(errorPos, Res.AmbiguousIndexerInvocation, + GetTypeName(expr.Type)); + } + } + } + + static bool IsPredefinedType(Type type) { + foreach (Type t in predefinedTypes) if (t == type) return true; + return false; + } + + static bool IsNullableType(Type type) { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + static Type GetNonNullableType(Type type) { + return IsNullableType(type) ? type.GetGenericArguments()[0] : type; + } + + static string GetTypeName(Type type) { + Type baseType = GetNonNullableType(type); + string s = baseType.Name; + if (type != baseType) s += '?'; + return s; + } + + static bool IsNumericType(Type type) { + return GetNumericTypeKind(type) != 0; + } + + static bool IsSignedIntegralType(Type type) { + return GetNumericTypeKind(type) == 2; + } + + static bool IsUnsignedIntegralType(Type type) { + return GetNumericTypeKind(type) == 3; + } + + static int GetNumericTypeKind(Type type) { + type = GetNonNullableType(type); + if (type.IsEnum) return 0; + switch (Type.GetTypeCode(type)) { + case TypeCode.Char: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return 1; + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + return 2; + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return 3; + default: + return 0; + } + } + + static bool IsEnumType(Type type) { + return GetNonNullableType(type).IsEnum; + } + + void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) { + Expression[] args = new Expression[] { expr }; + MethodBase method; + if (FindMethod(signatures, "F", false, args, out method) != 1) + throw ParseError(errorPos, Res.IncompatibleOperand, + opName, GetTypeName(args[0].Type)); + expr = args[0]; + } + + void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos) { + Expression[] args = new Expression[] { left, right }; + MethodBase method; + if (FindMethod(signatures, "F", false, args, out method) != 1) + throw IncompatibleOperandsError(opName, left, right, errorPos); + left = args[0]; + right = args[1]; + } + + Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos) { + return ParseError(pos, Res.IncompatibleOperands, + opName, GetTypeName(left.Type), GetTypeName(right.Type)); + } + + MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) { + BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | + (staticAccess ? BindingFlags.Static : BindingFlags.Instance); + foreach (Type t in SelfAndBaseTypes(type)) { + MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, + flags, Type.FilterNameIgnoreCase, memberName); + if (members.Length != 0) return members[0]; + } + return null; + } + + int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method) { + BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | + (staticAccess ? BindingFlags.Static : BindingFlags.Instance); + foreach (Type t in SelfAndBaseTypes(type)) { + MemberInfo[] members = t.FindMembers(MemberTypes.Method, + flags, Type.FilterNameIgnoreCase, methodName); + int count = FindBestMethod(members.Cast(), args, out method); + if (count != 0) return count; + } + method = null; + return 0; + } + + int FindIndexer(Type type, Expression[] args, out MethodBase method) { + foreach (Type t in SelfAndBaseTypes(type)) { + MemberInfo[] members = t.GetDefaultMembers(); + if (members.Length != 0) { + IEnumerable methods = members. + OfType(). + Select(p => (MethodBase)p.GetGetMethod()). + Where(m => m != null); + int count = FindBestMethod(methods, args, out method); + if (count != 0) return count; + } + } + method = null; + return 0; + } + + static IEnumerable SelfAndBaseTypes(Type type) { + if (type.IsInterface) { + List types = new List(); + AddInterface(types, type); + return types; + } + return SelfAndBaseClasses(type); + } + + static IEnumerable SelfAndBaseClasses(Type type) { + while (type != null) { + yield return type; + type = type.BaseType; + } + } + + static void AddInterface(List types, Type type) { + if (!types.Contains(type)) { + types.Add(type); + foreach (Type t in type.GetInterfaces()) AddInterface(types, t); + } + } + + class MethodData + { + public MethodBase MethodBase; + public ParameterInfo[] Parameters; + public Expression[] Args; + } + + int FindBestMethod(IEnumerable methods, Expression[] args, out MethodBase method) { + MethodData[] applicable = methods. + Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }). + Where(m => IsApplicable(m, args)). + ToArray(); + if (applicable.Length > 1) { + applicable = applicable. + Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))). + ToArray(); + } + if (applicable.Length == 1) { + MethodData md = applicable[0]; + for (int i = 0; i < args.Length; i++) args[i] = md.Args[i]; + method = md.MethodBase; + } + else { + method = null; + } + return applicable.Length; + } + + bool IsApplicable(MethodData method, Expression[] args) { + if (method.Parameters.Length != args.Length) return false; + Expression[] promotedArgs = new Expression[args.Length]; + for (int i = 0; i < args.Length; i++) { + ParameterInfo pi = method.Parameters[i]; + if (pi.IsOut) return false; + Expression promoted = PromoteExpression(args[i], pi.ParameterType, false); + if (promoted == null) return false; + promotedArgs[i] = promoted; + } + method.Args = promotedArgs; + return true; + } + + Expression PromoteExpression(Expression expr, Type type, bool exact) { + if (expr.Type == type) return expr; + if (expr is ConstantExpression) { + ConstantExpression ce = (ConstantExpression)expr; + if (ce == nullLiteral) { + if (!type.IsValueType || IsNullableType(type)) + return Expression.Constant(null, type); + } + else { + string text; + if (literals.TryGetValue(ce, out text)) { + Type target = GetNonNullableType(type); + Object value = null; + switch (Type.GetTypeCode(ce.Type)) { + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + value = ParseNumber(text, target); + break; + case TypeCode.Double: + if (target == typeof(decimal)) value = ParseNumber(text, target); + break; + case TypeCode.String: + value = ParseEnum(text, target); + break; + } + if (value != null) + return Expression.Constant(value, type); + } + } + } + if (IsCompatibleWith(expr.Type, type)) { + if (type.IsValueType || exact) return Expression.Convert(expr, type); + return expr; + } + return null; + } + + static object ParseNumber(string text, Type type) { + switch (Type.GetTypeCode(GetNonNullableType(type))) { + case TypeCode.SByte: + sbyte sb; + if (sbyte.TryParse(text, out sb)) return sb; + break; + case TypeCode.Byte: + byte b; + if (byte.TryParse(text, out b)) return b; + break; + case TypeCode.Int16: + short s; + if (short.TryParse(text, out s)) return s; + break; + case TypeCode.UInt16: + ushort us; + if (ushort.TryParse(text, out us)) return us; + break; + case TypeCode.Int32: + int i; + if (int.TryParse(text, out i)) return i; + break; + case TypeCode.UInt32: + uint ui; + if (uint.TryParse(text, out ui)) return ui; + break; + case TypeCode.Int64: + long l; + if (long.TryParse(text, out l)) return l; + break; + case TypeCode.UInt64: + ulong ul; + if (ulong.TryParse(text, out ul)) return ul; + break; + case TypeCode.Single: + float f; + if (float.TryParse(text, out f)) return f; + break; + case TypeCode.Double: + double d; + if (double.TryParse(text, out d)) return d; + break; + case TypeCode.Decimal: + decimal e; + if (decimal.TryParse(text, out e)) return e; + break; + } + return null; + } + + static object ParseEnum(string name, Type type) { + if (type.IsEnum) { + MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field, + BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static, + Type.FilterNameIgnoreCase, name); + if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null); + } + return null; + } + + static bool IsCompatibleWith(Type source, Type target) { + if (source == target) return true; + if (!target.IsValueType) return target.IsAssignableFrom(source); + Type st = GetNonNullableType(source); + Type tt = GetNonNullableType(target); + if (st != source && tt == target) return false; + TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st); + TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt); + switch (sc) { + case TypeCode.SByte: + switch (tc) { + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.Byte: + switch (tc) { + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.Int16: + switch (tc) { + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.UInt16: + switch (tc) { + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.Int32: + switch (tc) { + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.UInt32: + switch (tc) { + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.Int64: + switch (tc) { + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.UInt64: + switch (tc) { + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + return true; + } + break; + case TypeCode.Single: + switch (tc) { + case TypeCode.Single: + case TypeCode.Double: + return true; + } + break; + default: + if (st == tt) return true; + break; + } + return false; + } + + static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2) { + bool better = false; + for (int i = 0; i < args.Length; i++) { + int c = CompareConversions(args[i].Type, + m1.Parameters[i].ParameterType, + m2.Parameters[i].ParameterType); + if (c < 0) return false; + if (c > 0) better = true; + } + return better; + } + + // Return 1 if s -> t1 is a better conversion than s -> t2 + // Return -1 if s -> t2 is a better conversion than s -> t1 + // Return 0 if neither conversion is better + static int CompareConversions(Type s, Type t1, Type t2) { + if (t1 == t2) return 0; + if (s == t1) return 1; + if (s == t2) return -1; + bool t1t2 = IsCompatibleWith(t1, t2); + bool t2t1 = IsCompatibleWith(t2, t1); + if (t1t2 && !t2t1) return 1; + if (t2t1 && !t1t2) return -1; + if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1; + if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1; + return 0; + } + + Expression GenerateEqual(Expression left, Expression right) { + return Expression.Equal(left, right); + } + + Expression GenerateNotEqual(Expression left, Expression right) { + return Expression.NotEqual(left, right); + } + + Expression GenerateGreaterThan(Expression left, Expression right) { + if (left.Type == typeof(string)) { + return Expression.GreaterThan( + GenerateStaticMethodCall("Compare", left, right), + Expression.Constant(0) + ); + } + return Expression.GreaterThan(left, right); + } + + Expression GenerateGreaterThanEqual(Expression left, Expression right) { + if (left.Type == typeof(string)) { + return Expression.GreaterThanOrEqual( + GenerateStaticMethodCall("Compare", left, right), + Expression.Constant(0) + ); + } + return Expression.GreaterThanOrEqual(left, right); + } + + Expression GenerateLessThan(Expression left, Expression right) { + if (left.Type == typeof(string)) { + return Expression.LessThan( + GenerateStaticMethodCall("Compare", left, right), + Expression.Constant(0) + ); + } + return Expression.LessThan(left, right); + } + + Expression GenerateLessThanEqual(Expression left, Expression right) { + if (left.Type == typeof(string)) { + return Expression.LessThanOrEqual( + GenerateStaticMethodCall("Compare", left, right), + Expression.Constant(0) + ); + } + return Expression.LessThanOrEqual(left, right); + } + + Expression GenerateAdd(Expression left, Expression right) { + if (left.Type == typeof(string) && right.Type == typeof(string)) { + return GenerateStaticMethodCall("Concat", left, right); + } + return Expression.Add(left, right); + } + + Expression GenerateSubtract(Expression left, Expression right) { + return Expression.Subtract(left, right); + } + + Expression GenerateStringConcat(Expression left, Expression right) { + return Expression.Call( + null, + typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }), + new[] { left, right }); + } + + MethodInfo GetStaticMethod(string methodName, Expression left, Expression right) { + return left.Type.GetMethod(methodName, new[] { left.Type, right.Type }); + } + + Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) { + return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right }); + } + + void SetTextPos(int pos) { + textPos = pos; + ch = textPos < textLen ? text[textPos] : '\0'; + } + + void NextChar() { + if (textPos < textLen) textPos++; + ch = textPos < textLen ? text[textPos] : '\0'; + } + + void NextToken() { + while (Char.IsWhiteSpace(ch)) NextChar(); + TokenId t; + int tokenPos = textPos; + switch (ch) { + case '!': + NextChar(); + if (ch == '=') { + NextChar(); + t = TokenId.ExclamationEqual; + } + else { + t = TokenId.Exclamation; + } + break; + case '%': + NextChar(); + t = TokenId.Percent; + break; + case '&': + NextChar(); + if (ch == '&') { + NextChar(); + t = TokenId.DoubleAmphersand; + } + else { + t = TokenId.Amphersand; + } + break; + case '(': + NextChar(); + t = TokenId.OpenParen; + break; + case ')': + NextChar(); + t = TokenId.CloseParen; + break; + case '*': + NextChar(); + t = TokenId.Asterisk; + break; + case '+': + NextChar(); + t = TokenId.Plus; + break; + case ',': + NextChar(); + t = TokenId.Comma; + break; + case '-': + NextChar(); + t = TokenId.Minus; + break; + case '.': + NextChar(); + t = TokenId.Dot; + break; + case '/': + NextChar(); + t = TokenId.Slash; + break; + case ':': + NextChar(); + t = TokenId.Colon; + break; + case '<': + NextChar(); + if (ch == '=') { + NextChar(); + t = TokenId.LessThanEqual; + } + else if (ch == '>') { + NextChar(); + t = TokenId.LessGreater; + } + else { + t = TokenId.LessThan; + } + break; + case '=': + NextChar(); + if (ch == '=') { + NextChar(); + t = TokenId.DoubleEqual; + } + else { + t = TokenId.Equal; + } + break; + case '>': + NextChar(); + if (ch == '=') { + NextChar(); + t = TokenId.GreaterThanEqual; + } + else { + t = TokenId.GreaterThan; + } + break; + case '?': + NextChar(); + t = TokenId.Question; + break; + case '[': + NextChar(); + t = TokenId.OpenBracket; + break; + case ']': + NextChar(); + t = TokenId.CloseBracket; + break; + case '|': + NextChar(); + if (ch == '|') { + NextChar(); + t = TokenId.DoubleBar; + } + else { + t = TokenId.Bar; + } + break; + case '"': + case '\'': + char quote = ch; + do { + NextChar(); + while (textPos < textLen && ch != quote) NextChar(); + if (textPos == textLen) + throw ParseError(textPos, Res.UnterminatedStringLiteral); + NextChar(); + } while (ch == quote); + t = TokenId.StringLiteral; + break; + default: + if (Char.IsLetter(ch) || ch == '@' || ch == '_') { + do { + NextChar(); + } while (Char.IsLetterOrDigit(ch) || ch == '_'); + t = TokenId.Identifier; + break; + } + if (Char.IsDigit(ch)) { + t = TokenId.IntegerLiteral; + do { + NextChar(); + } while (Char.IsDigit(ch)); + if (ch == '.') { + t = TokenId.RealLiteral; + NextChar(); + ValidateDigit(); + do { + NextChar(); + } while (Char.IsDigit(ch)); + } + if (ch == 'E' || ch == 'e') { + t = TokenId.RealLiteral; + NextChar(); + if (ch == '+' || ch == '-') NextChar(); + ValidateDigit(); + do { + NextChar(); + } while (Char.IsDigit(ch)); + } + if (ch == 'F' || ch == 'f') NextChar(); + break; + } + if (textPos == textLen) { + t = TokenId.End; + break; + } + throw ParseError(textPos, Res.InvalidCharacter, ch); + } + token.id = t; + token.text = text.Substring(tokenPos, textPos - tokenPos); + token.pos = tokenPos; + } + + bool TokenIdentifierIs(string id) { + return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase); + } + + string GetIdentifier() { + ValidateToken(TokenId.Identifier, Res.IdentifierExpected); + string id = token.text; + if (id.Length > 1 && id[0] == '@') id = id.Substring(1); + return id; + } + + void ValidateDigit() { + if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected); + } + + void ValidateToken(TokenId t, string errorMessage) { + if (token.id != t) throw ParseError(errorMessage); + } + + void ValidateToken(TokenId t) { + if (token.id != t) throw ParseError(Res.SyntaxError); + } + + Exception ParseError(string format, params object[] args) { + return ParseError(token.pos, format, args); + } + + Exception ParseError(int pos, string format, params object[] args) { + return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos); + } + + static Dictionary CreateKeywords() { + Dictionary d = new Dictionary(StringComparer.OrdinalIgnoreCase); + d.Add("true", trueLiteral); + d.Add("false", falseLiteral); + d.Add("null", nullLiteral); + d.Add(keywordIt, keywordIt); + d.Add(keywordIif, keywordIif); + d.Add(keywordNew, keywordNew); + foreach (Type type in predefinedTypes) d.Add(type.Name, type); + return d; + } + } + + static class Res + { + public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once"; + public const string ExpressionTypeMismatch = "Expression of type '{0}' expected"; + public const string ExpressionExpected = "Expression expected"; + public const string InvalidCharacterLiteral = "Character literal must contain exactly one character"; + public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'"; + public const string InvalidRealLiteral = "Invalid real literal '{0}'"; + public const string UnknownIdentifier = "Unknown identifier '{0}'"; + public const string NoItInScope = "No 'it' is in scope"; + public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments"; + public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'"; + public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other"; + public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other"; + public const string MissingAsClause = "Expression is missing an 'as' clause"; + public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression"; + public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form"; + public const string NoMatchingConstructor = "No matching constructor in type '{0}'"; + public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor"; + public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'"; + public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'"; + public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible"; + public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value"; + public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'"; + public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'"; + public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists"; + public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported"; + public const string InvalidIndex = "Array index must be an integer expression"; + public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'"; + public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'"; + public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'"; + public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'"; + public const string UnterminatedStringLiteral = "Unterminated string literal"; + public const string InvalidCharacter = "Syntax error '{0}'"; + public const string DigitExpected = "Digit expected"; + public const string SyntaxError = "Syntax error"; + public const string TokenExpected = "{0} expected"; + public const string ParseExceptionFormat = "{0} (at index {1})"; + public const string ColonExpected = "':' expected"; + public const string OpenParenExpected = "'(' expected"; + public const string CloseParenOrOperatorExpected = "')' or operator expected"; + public const string CloseParenOrCommaExpected = "')' or ',' expected"; + public const string DotOrOpenParenExpected = "'.' or '(' expected"; + public const string OpenBracketExpected = "'[' expected"; + public const string CloseBracketOrCommaExpected = "']' or ',' expected"; + public const string IdentifierExpected = "Identifier expected"; + } +} diff --git a/Infrastructure/Filter.cs b/Infrastructure/Filter.cs new file mode 100644 index 00000000..4fa6782b --- /dev/null +++ b/Infrastructure/Filter.cs @@ -0,0 +1,9 @@ +namespace Infrastructure +{ + public class Filter + { + public string Key { get; set; } + public string Value { get; set; } + public string Contrast { get; set; } + } +} \ No newline at end of file diff --git a/Infrastructure/GenerateId.cs b/Infrastructure/GenerateId.cs new file mode 100644 index 00000000..ca73e230 --- /dev/null +++ b/Infrastructure/GenerateId.cs @@ -0,0 +1,111 @@ +// *********************************************************************** +// Assembly : FairUtility +// Author : Yubao Li +// Created : 10-13-2015 +// +// Last Modified By : Yubao Li +// Last Modified On : 10-13-2015 +// *********************************************************************** +// +// Copyright (c) . All rights reserved. +// +// 创建唯一ID +// *********************************************************************** + +using System; + +namespace Infrastructure +{ + public class GenerateId + { + /// + /// 生成一个长整型,可以转成19字节长的字符串 + /// + /// System.Int64. + public static long GenerateLong() + { + byte[] buffer = Guid.NewGuid().ToByteArray(); + return BitConverter.ToInt64(buffer, 0); + } + + /// + /// 生成16个字节长度的数据与英文组合串 + /// + public static string GenerateStr() + { + long i = 1; + + foreach (byte b in Guid.NewGuid().ToByteArray()) + { + i *= ((int)b + 1); + } + + return string.Format("{0:x}", i - DateTime.Now.Ticks); + } + + /// + /// 唯一订单号生成 + /// + /// + public static string GenerateOrderNumber() + { + string strDateTimeNumber = DateTime.Now.ToString("yyyyMMddHHmmssffff"); + string strRandomResult = NextRandom(1000, 1).ToString("0000"); + + return strDateTimeNumber + strRandomResult; + } + + /// + /// 参考:msdn上的RNGCryptoServiceProvider例子 + /// + /// + /// + /// + private static int NextRandom(int numSeeds, int length) + { + // Create a byte array to hold the random value. + byte[] randomNumber = new byte[length]; + // Create a new instance of the RNGCryptoServiceProvider. + System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); + // Fill the array with a random value. + rng.GetBytes(randomNumber); + // Convert the byte to an uint value to make the modulus operation easier. + uint randomResult = 0x0; + for (int i = 0; i < length; i++) + { + randomResult |= ((uint)randomNumber[i] << ((length - 1 - i) * 8)); + } + + return (int)(randomResult % numSeeds) + 1; + } + + /// + /// 创建11位的英文与数字组合 + /// + /// System.String. + public static string ShortStr() + { + return Convert(GenerateLong()); + } + + static string Seq = "s9LFkgy5RovixI1aOf8UhdY3r4DMplQZJXPqebE0WSjBn7wVzmN2Gc6THCAKut"; + /// + /// 10进制转换为62进制 + /// + /// + /// + + private static string Convert(long id) + { + if (id < 62) + { + return Seq[(int)id].ToString(); + } + int y = (int)(id % 62); + long x = (long)(id / 62); + + return Convert(x) + Seq[y]; + } + + } +} \ No newline at end of file diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj index ee06a4d5..1ff7ab97 100644 --- a/Infrastructure/Infrastructure.csproj +++ b/Infrastructure/Infrastructure.csproj @@ -30,6 +30,16 @@ 4 + + ..\packages\AutoMapper.4.1.0\lib\net45\AutoMapper.dll + + + ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll + + + False + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + @@ -40,9 +50,22 @@ - - + + + + + + + + + + + + + + + + + + + + Debug + AnyCPU + {6108DA8E-92A1-4ABE-B9F5-26D64D55CA2C} + Library + Properties + OpenAuth.Domain + OpenAuth.Domain + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenAuth.Domain/Org.cs b/OpenAuth.Domain/Org.cs new file mode 100644 index 00000000..209dc6e4 --- /dev/null +++ b/OpenAuth.Domain/Org.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class Org + { + public int Id { get; set; } + public string CascadeId { get; set; } + public string Name { get; set; } + public string HotKey { get; set; } + public int ParentId { get; set; } + public string ParentName { get; set; } + public bool IsLeaf { get; set; } + public bool IsAutoExpand { get; set; } + public string IconName { get; set; } + public int Status { get; set; } + public int Type { get; set; } + public string BizCode { get; set; } + public string CustomCode { get; set; } + public System.DateTime CreateTime { get; set; } + public int CreateId { get; set; } + public int SortNo { get; set; } + } +} diff --git a/OpenAuth.Domain/Page.cs b/OpenAuth.Domain/Page.cs new file mode 100644 index 00000000..14a6968f --- /dev/null +++ b/OpenAuth.Domain/Page.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class Page + { + public int Id { get; set; } + public int ModuleId { get; set; } + public string Name { get; set; } + public string Url { get; set; } + public int Type { get; set; } + public bool Enabled { get; set; } + public bool IsDefault { get; set; } + public string Icon { get; set; } + public string IconBig { get; set; } + public string Vector { get; set; } + public int SortNo { get; set; } + } +} diff --git a/OpenAuth.Domain/PageElement.cs b/OpenAuth.Domain/PageElement.cs new file mode 100644 index 00000000..1026a286 --- /dev/null +++ b/OpenAuth.Domain/PageElement.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class PageElement + { + public int Id { get; set; } + public string DomId { get; set; } + public string Name { get; set; } + public int Type { get; set; } + public int ModuleId { get; set; } + public string Remark { get; set; } + } +} diff --git a/OpenAuth.Domain/PageElementGrant.cs b/OpenAuth.Domain/PageElementGrant.cs new file mode 100644 index 00000000..5c91415f --- /dev/null +++ b/OpenAuth.Domain/PageElementGrant.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class PageElementGrant + { + public int Id { get; set; } + public int ElementId { get; set; } + public int UserId { get; set; } + public int RoleId { get; set; } + public int PostId { get; set; } + public int GrantType { get; set; } + } +} diff --git a/OpenAuth.Domain/Role.cs b/OpenAuth.Domain/Role.cs index 8c4e9c7b..a6d2082d 100644 --- a/OpenAuth.Domain/Role.cs +++ b/OpenAuth.Domain/Role.cs @@ -1,15 +1,17 @@ -namespace OpenAuth.Domain -{ - public partial class Role - { - public string RoleId { get; set; } - public string ParentId { get; set; } - public string FullName { get; set; } - public string Category { get; set; } - public string Description { get; set; } - public bool Enabled { get; set; } - public int SortCode { get; set; } - public bool DeleteMark { get; set; } - public string DepartmentId { get; set; } - } -} +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class Role + { + public int Id { get; set; } + public string Name { get; set; } + public int Status { get; set; } + public int Type { get; set; } + public System.DateTime CreateTime { get; set; } + public string CreateId { get; set; } + public int CreateOrgId { get; set; } + public string CreateOrgCascadeId { get; set; } + } +} diff --git a/OpenAuth.Domain/RoleMenu.cs b/OpenAuth.Domain/RoleMenu.cs deleted file mode 100644 index 156ff712..00000000 --- a/OpenAuth.Domain/RoleMenu.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace OpenAuth.Domain -{ - public partial class RoleMenu - { - public string RoleMenuId { get; set; } - public string RoleId { get; set; } - public string MenuId { get; set; } - } -} diff --git a/OpenAuth.Domain/RoleMenuButton.cs b/OpenAuth.Domain/RoleMenuButton.cs deleted file mode 100644 index 5f125e9e..00000000 --- a/OpenAuth.Domain/RoleMenuButton.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace OpenAuth.Domain -{ - public partial class RoleMenuButton - { - public string RoleMenuButtonId { get; set; } - public string RoleId { get; set; } - public string MenuId { get; set; } - public string ButtonId { get; set; } - } -} diff --git a/OpenAuth.Domain/User.cs b/OpenAuth.Domain/User.cs index bdab39ea..ff21a5ab 100644 --- a/OpenAuth.Domain/User.cs +++ b/OpenAuth.Domain/User.cs @@ -1,25 +1,19 @@ -using System; - -namespace OpenAuth.Domain -{ - public partial class User - { - public string UserId { get; set; } - public string Account { get; set; } - public string Password { get; set; } - public string RealName { get; set; } - public string RoleId { get; set; } - public bool Enabled { get; set; } - public bool DeleteMark { get; set; } - - public void CheckLogin(string password) - { - if(this.Password != password) - throw new Exception(""); - if(!this.Enabled) - throw new Exception("ûѾͣ"); - if (DeleteMark) - throw new Exception("˺Ѿɾ"); - } - } -} +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class User + { + public int Id { get; set; } + public string Account { get; set; } + public string Password { get; set; } + public string Name { get; set; } + public int Sex { get; set; } + public int Status { get; set; } + public int Type { get; set; } + public string BizCode { get; set; } + public System.DateTime CreateTime { get; set; } + public int CreateId { get; set; } + } +} diff --git a/OpenAuth.Domain/UserCfg.cs b/OpenAuth.Domain/UserCfg.cs new file mode 100644 index 00000000..027e0d7d --- /dev/null +++ b/OpenAuth.Domain/UserCfg.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class UserCfg + { + public int Id { get; set; } + public string Theme { get; set; } + public string Skin { get; set; } + public string NavBarStyle { get; set; } + public string TabFocusColor { get; set; } + public int NavTabIndex { get; set; } + } +} diff --git a/OpenAuth.Domain/UserDepartment.cs b/OpenAuth.Domain/UserDepartment.cs deleted file mode 100644 index 95894072..00000000 --- a/OpenAuth.Domain/UserDepartment.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace OpenAuth.Domain -{ - public partial class UserDepartment - { - public string UserDepartmentId { get; set; } - public string DepartmentId { get; set; } - public string UserId { get; set; } - } -} diff --git a/OpenAuth.Domain/UserExt.cs b/OpenAuth.Domain/UserExt.cs new file mode 100644 index 00000000..5bfb1f04 --- /dev/null +++ b/OpenAuth.Domain/UserExt.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class UserExt + { + public int Id { get; set; } + public string Email { get; set; } + public string Phone_ { get; set; } + public string Mobile { get; set; } + public string Address { get; set; } + public string Zip { get; set; } + public string Birthday { get; set; } + public string IdCard { get; set; } + public string QQ { get; set; } + public string DynamicField { get; set; } + public int ByteArrayId { get; set; } + public string Remark { get; set; } + public string Field1 { get; set; } + public string Field2 { get; set; } + public string Field3 { get; set; } + } +} diff --git a/OpenAuth.Domain/UserModule.cs b/OpenAuth.Domain/UserModule.cs new file mode 100644 index 00000000..1b619c29 --- /dev/null +++ b/OpenAuth.Domain/UserModule.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class UserModule + { + public int Id { get; set; } + public int UserId { get; set; } + public int ModuleId { get; set; } + public int Type { get; set; } + public System.DateTime OperateTime { get; set; } + public int OperatorId { get; set; } + } +} diff --git a/OpenAuth.Domain/UserOrg.cs b/OpenAuth.Domain/UserOrg.cs new file mode 100644 index 00000000..6f4bbd77 --- /dev/null +++ b/OpenAuth.Domain/UserOrg.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class UserOrg + { + public int Id { get; set; } + public int OrgId { get; set; } + public int UserId { get; set; } + public System.DateTime OperateTime { get; set; } + public int OperatorId { get; set; } + } +} diff --git a/OpenAuth.Domain/UserRole.cs b/OpenAuth.Domain/UserRole.cs index 7e71ba37..dc4b05d3 100644 --- a/OpenAuth.Domain/UserRole.cs +++ b/OpenAuth.Domain/UserRole.cs @@ -1,9 +1,14 @@ -namespace OpenAuth.Domain -{ - public partial class UserRole - { - public string UserRoleId { get; set; } - public string UserId { get; set; } - public string RoleId { get; set; } - } -} +using System; +using System.Collections.Generic; + +namespace OpenAuth.Domain +{ + public partial class UserRole + { + public int Id { get; set; } + public int RoleId { get; set; } + public int UserId { get; set; } + public System.DateTime OperateTime { get; set; } + public int OperatorId { get; set; } + } +} diff --git a/OpenAuth.Domain/sysdiagram.cs b/OpenAuth.Domain/sysdiagram.cs deleted file mode 100644 index 5327b3d7..00000000 --- a/OpenAuth.Domain/sysdiagram.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace OpenAuth.Domain -{ - public partial class sysdiagram - { - public string name { get; set; } - public int principal_id { get; set; } - public int diagram_id { get; set; } - public Nullable version { get; set; } - public byte[] definition { get; set; } - } -} diff --git a/OpenAuth.Mvc/AutofacExt.cs b/OpenAuth.Mvc/AutofacExt.cs new file mode 100644 index 00000000..5d974b4b --- /dev/null +++ b/OpenAuth.Mvc/AutofacExt.cs @@ -0,0 +1,57 @@ +// *********************************************************************** +// Assembly : OpenAuth.Mvc +// Author : yubaolee +// Created : 10-26-2015 +// +// Last Modified By : yubaolee +// Last Modified On : 10-26-2015 +// *********************************************************************** +// +// Copyright (c) www.cnblogs.com/yubaolee. All rights reserved. +// +// IOCʼ +// *********************************************************************** + +using System.Reflection; +using System.Web.Mvc; +using Autofac; +using Autofac.Integration.Mvc; +using OpenAuth.App; +using OpenAuth.Domain.Interface; +using OpenAuth.Repository; + +namespace OpenAuth.Mvc +{ + static internal class AutofacExt + { + public static void InitAutofac() + { + var builder = new ContainerBuilder(); + + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType(); + builder.RegisterType(); + + // Register your MVC controllers. + builder.RegisterControllers(typeof (MvcApplication).Assembly); + + // OPTIONAL: Register model binders that require DI. + builder.RegisterModelBinders(Assembly.GetExecutingAssembly()); + builder.RegisterModelBinderProvider(); + + // OPTIONAL: Register web abstractions like HttpContextBase. + builder.RegisterModule(); + + // OPTIONAL: Enable property injection in view pages. + builder.RegisterSource(new ViewRegistrationSource()); + + // OPTIONAL: Enable property injection into action filters. + builder.RegisterFilterProvider(); + + // Set the dependency resolver to be Autofac. + var container = builder.Build(); + DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); + } + } +} \ No newline at end of file diff --git a/OpenAuth.Mvc/Controllers/HomeController.cs b/OpenAuth.Mvc/Controllers/HomeController.cs index 71172981..f77d6bb7 100644 --- a/OpenAuth.Mvc/Controllers/HomeController.cs +++ b/OpenAuth.Mvc/Controllers/HomeController.cs @@ -21,9 +21,9 @@ namespace OpenAuth.Mvc.Controllers return View(); } - public ContentResult Main() + public ActionResult Main() { - return Content("欢迎使用基于DDD的权限管理系统"); + return View(); } public ActionResult Login() diff --git a/OpenAuth.Mvc/Controllers/ModuleManagerController.cs b/OpenAuth.Mvc/Controllers/ModuleManagerController.cs new file mode 100644 index 00000000..380fec5f --- /dev/null +++ b/OpenAuth.Mvc/Controllers/ModuleManagerController.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace OpenAuth.Mvc.Controllers +{ + public class ModuleManagerController : BaseController + { + // + // GET: /Modu/ + public ActionResult Index() + { + return View(); + } + } +} \ No newline at end of file diff --git a/OpenAuth.Mvc/Controllers/OrgManagerController.cs b/OpenAuth.Mvc/Controllers/OrgManagerController.cs new file mode 100644 index 00000000..d31a01a5 --- /dev/null +++ b/OpenAuth.Mvc/Controllers/OrgManagerController.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using Infrastructure; +using OpenAuth.App; + +namespace OpenAuth.Mvc.Controllers +{ + public class OrgManagerController : BaseController + { + private OrgManagerApp _orgApp; + + public OrgManagerController() + { + _orgApp = (OrgManagerApp) DependencyResolver.Current.GetService(typeof (OrgManagerApp)); + } + // + // GET: /OrgManager/ + public ActionResult Index() + { + return View(); + } + + + public string LoadOrg() + { + var orgs = _orgApp.GetAll(); + return JsonHelper.Instance.Serialize(orgs); + } + } +} \ No newline at end of file diff --git a/OpenAuth.Mvc/Controllers/UserManagerController.cs b/OpenAuth.Mvc/Controllers/UserManagerController.cs new file mode 100644 index 00000000..9e07099b --- /dev/null +++ b/OpenAuth.Mvc/Controllers/UserManagerController.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace OpenAuth.Mvc.Controllers +{ + public class UserManagerController : Controller + { + // + // GET: /UserManager/ + public ActionResult Index() + { + return View(); + } + } +} \ No newline at end of file diff --git a/OpenAuth.Mvc/Global.asax.cs b/OpenAuth.Mvc/Global.asax.cs index ab7d6d2f..23c9f1c2 100644 --- a/OpenAuth.Mvc/Global.asax.cs +++ b/OpenAuth.Mvc/Global.asax.cs @@ -8,6 +8,7 @@ using System.Web.Optimization; using System.Web.Routing; using Autofac; using Autofac.Integration.Mvc; +using Infrastructure; using OpenAuth.App; using OpenAuth.Domain.Interface; using OpenAuth.Repository; @@ -18,41 +19,15 @@ namespace OpenAuth.Mvc { protected void Application_Start() { - InitAutofac(); + AutofacExt.InitAutofac(); AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); - } - private static void InitAutofac() - { - var builder = new ContainerBuilder(); - - builder.RegisterType().As(); - builder.RegisterType(); - - // Register your MVC controllers. - builder.RegisterControllers(typeof (MvcApplication).Assembly); - - // OPTIONAL: Register model binders that require DI. - builder.RegisterModelBinders(Assembly.GetExecutingAssembly()); - builder.RegisterModelBinderProvider(); - - // OPTIONAL: Register web abstractions like HttpContextBase. - builder.RegisterModule(); - - // OPTIONAL: Enable property injection in view pages. - builder.RegisterSource(new ViewRegistrationSource()); - - // OPTIONAL: Enable property injection into action filters. - builder.RegisterFilterProvider(); - - // Set the dependency resolver to be Autofac. - var container = builder.Build(); - DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); + LogHelper.Log("启动Web"); } } } diff --git a/OpenAuth.Mvc/OpenAuth.Mvc.csproj b/OpenAuth.Mvc/OpenAuth.Mvc.csproj index 40916711..b22de4cd 100644 --- a/OpenAuth.Mvc/OpenAuth.Mvc.csproj +++ b/OpenAuth.Mvc/OpenAuth.Mvc.csproj @@ -120,8 +120,12 @@ + + + + Global.asax @@ -129,6 +133,7 @@ + @@ -142,14 +147,7 @@ - - - - - - - @@ -563,6 +561,7 @@ + @@ -604,6 +603,12 @@ + + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/OpenAuth.Mvc/Views/Home/Index.cshtml b/OpenAuth.Mvc/Views/Home/Index.cshtml index 4180a9a1..330067ae 100644 --- a/OpenAuth.Mvc/Views/Home/Index.cshtml +++ b/OpenAuth.Mvc/Views/Home/Index.cshtml @@ -206,7 +206,7 @@
  • 文件列表
  • -
  • 文件详解
  • +
  • 机构管理
  • 框架介绍
  • 页面结构
  • 框架初始化
  • @@ -221,59 +221,6 @@
  • 框架皮肤
  • 颜色值
-
    -
  • 标签navtab
  • -
  • 创建navtab
  • -
  • 参数及方法
  • -
  • 弹窗dialog
  • -
  • 创建dialog
  • -
  • 参数及方法
  • -
  • 信息提示alertmsg
  • -
  • 提示框alertmsg
  • -
  • 表单相关
  • -
  • 日期选择器
  • -
  • 微调器
  • -
  • 查找带回
  • -
  • 自动完成标签
  • -
  • 上传组件
  • -
  • 右键菜单
  • -
  • 右键菜单
  • -
-
    -
  • Ajax
  • -
  • 回调函数
  • -
  • 提交表单
  • -
  • 搜索表单
  • -
  • 加载(局部刷新)
  • -
  • 执行动作
  • -
-
    -
  • 普通表格
  • -
  • 表格样式
  • -
  • 字段排序
  • -
  • 分页组件
  • -
  • 行选中操作
  • -
  • 固定表头
  • -
  • 可编辑表格
  • -
  • Datagrid
  • -
  • datagrid示例
  • -
  • datagrid参数
  • -
  • columns参数
  • -
-
    -
  • 图形报表(插件)
  • -
  • Highcharts图表
  • -
  • ECharts图表
  • -
-
    -
  • 其他插件
  • -
  • zTree
  • -
  • 复选/单选
  • -
  • 下拉选择框
  • -
  • 表单验证
  • -
  • KindEditor
  • -
  • Ajax Download
  • -