DDD领域模型之分配权限(十三)

权限分配和权限查找。

在DDD.Domain工程中新建:BAS_PermissionAssign类

public partial class BAS_PermissionAssgin:AggreateRoot
    {
        private IRepository<BAS_PermissionAssgin> irepository;
        public BAS_PermissionAssgin(IRepository<BAS_PermissionAssgin> irepository)
        {
            this.irepository = irepository;
        }

        public BAS_PermissionAssgin() { }
        /// <summary>
        /// 创建权限分配
        /// </summary>
        /// <param name="identitycontainer"></param>
        /// <param name="objectcontainer"></param>
        /// <param name="permissioncontainer"></param>
        public void CreatePermissionAssign(BAS_IdentityContianer identitycontainer,
            BAS_ObejctContainer objectcontainer,BAS_PermissionConatiner permissioncontainer)
        {
            var bas_permissionassign = new BAS_PermissionAssgin();
            bas_permissionassign.Id = base.Id;
            bas_permissionassign.BAS_IdentityContianer = identitycontainer;
            bas_permissionassign.BAS_ObejctContainer = objectcontainer;
            bas_permissionassign.BAS_PermissionConatiner = permissioncontainer;
            irepository.Create(bas_permissionassign);
        }

        /// <summary>
        /// 判断某个对象ID是否进行了权限分配
        /// </summary>
        /// <param name="obj_id"></param>
        /// <returns></returns>
        public bool GetPermissionAssignObjectIsExists(Guid obj_id)
        {
            return irepository.GetByCondition(p => p.BAS_ObejctContainer.Id == obj_id,
                p => true).Count > 0;
        }

     
        /// <summary>
        /// 根据权限容器获取权限分配信息
        /// </summary>
        /// <param name="permissioncontainer"></param>
        /// <returns></returns>
        public List<BAS_PermissionAssgin> GetPAByPermissionContainer(BAS_PermissionConatiner permissioncontainer)
        {
            return irepository.GetByCondition(p => p.BAS_PermissionConatiner.Id == permissioncontainer.Id, p => true);
        }
       
        /// <summary>
        /// 根据对象容器获取权限分配信息
        /// </summary>
        /// <param name="objectcontainer"></param>
        /// <returns></returns>
        public List<BAS_PermissionAssgin> GetPAByObjectContainer(BAS_ObejctContainer objectcontainer)
        {
            return irepository.GetByCondition(p => p.BAS_ObejctContainer.Id == objectcontainer.Id, p => true);
        }

        /// <summary>
        /// 根据标识容器获取权限分配信息
        /// </summary>
        /// <param name="identitycontainer"></param>
        /// <returns></returns>
        public List<BAS_PermissionAssgin> GetPAByIdentityContainer(BAS_IdentityContianer identitycontainer)
        {
            return irepository.GetByCondition(p => p.BAS_IdentityContianer.Id == identitycontainer.Id, p => true);
        }
    }

序列化和反序列化的共用代码:

 public class Utils
    {
        /// <summary>
        /// 反序列化json字符串为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        public static T JsonDeserialize<T>(string jsonString)
        {
            var ser = new DataContractJsonSerializer(typeof(T));
            var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
            var obj = (T)ser.ReadObject(ms);
            return obj;
        }

        /// <summary>
        /// 序列化对象为json字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objects"></param>
        /// <returns></returns>
        public static string JsonSerialize<T>(T objects)
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, objects);
            var dataBytes = new byte[stream.Length];
            stream.Position = 0;
            stream.Read(dataBytes, 0, (int)stream.Length);
            return Encoding.UTF8.GetString(dataBytes);
        }
    }

 在DDD.Domain工程下DomainService文件夹BAS_PermissionAssignService

 

  public class BAS_PermissionAssignService<TAggreateRoot> where TAggreateRoot : class,
        IAggreateRoot
    {
        private IRepository<BAS_PermissionAssgin> irepositorypermissionassign;
        private IRepository<BAS_IdentityContianer> irepositoryidentitycontainer;
        private IRepository<BAS_ObejctContainer> irepositoryobjectcontainer;
        private IRepository<BAS_PermissionConatiner> irepositorypermissioncontainer;

        private IRepository<BAS_User> irepositoryuser;
        private IRepository<BAS_Department> irepositorydepartment;
        private IRepository<BAS_Post> irepositorypost;
        private IRepository<BAS_Role> irepositoryrole;

        private IRepository<BAS_Obejct> irepositoryobject;
        private IRepository<BAS_ObjectSet> irepositoryobjectset;
        private IRepository<BAS_Permission> irepositorypermission;
        private IRepository<BAS_PermissionSet> irepositorypermissionset;

        private IRepository<BAS_OOSet> irepositoryooset;

        public BAS_PermissionAssignService(IRepository<BAS_PermissionAssgin> irepositorypermissionassign,
        IRepository<BAS_IdentityContianer> irepositoryidentitycontainer,
         IRepository<BAS_ObejctContainer> irepositoryobjectcontainer,
         IRepository<BAS_PermissionConatiner> irepositorypermissioncontainer,

         IRepository<BAS_User> irepositoryuser,
         IRepository<BAS_Department> irepositorydepartment,
         IRepository<BAS_Post> irepositorypost,
        IRepository<BAS_Role> irepositoryrole,

         IRepository<BAS_Obejct> irepositoryobject,
         IRepository<BAS_ObjectSet> irepositoryobjectset,
        IRepository<BAS_Permission> irepositorypermission,
         IRepository<BAS_PermissionSet> irepositorypermissionset,
 IRepository<BAS_OOSet> irepositoryooset)
        {
            this.irepositorydepartment = irepositorydepartment;
            this.irepositoryidentitycontainer = irepositoryidentitycontainer;
            this.irepositoryobject = irepositoryobject;
            this.irepositoryobjectcontainer = irepositoryobjectcontainer;
            this.irepositoryobjectset = irepositoryobjectset;
            this.irepositoryooset = irepositoryooset;
            this.irepositorypermission = irepositorypermission;
            this.irepositorypermissionassign = irepositorypermissionassign;
            this.irepositorypermissioncontainer = irepositorypermissioncontainer;
            this.irepositorypermissionset = irepositorypermissionset;
            this.irepositorypost = irepositorypost;
            this.irepositoryrole = irepositoryrole;
            this.irepositoryuser = irepositoryuser;
        }

        /// <summary>
        /// 权限分配
        /// </summary>
        /// <param name="userno"></param>
        /// <param name="departmentname"></param>
        /// <param name="postname"></param>
        /// <param name="rolename"></param>
        /// <param name="objectname"></param>
        /// <param name="objectsetname"></param>
        /// <param name="permissionname"></param>
        /// <param name="permissionsetname"></param>
        public void CreatePermissionAssgin(string userno,string departmentname,
            string postname,string rolename,string objectname,string objectsetname,
            string permissionname,string permissionsetname)
        {
            BAS_IdentityContianer identitycontainer=null;
            BAS_ObejctContainer objectcontainer=null;
            BAS_PermissionConatiner permissioncontainer=null;

            if(!string.IsNullOrEmpty(userno))
            {
                var conid = irepositoryuser.GetByCondition(p => p.No == userno, p => true).SingleOrDefault().Con_Id;
                identitycontainer =
                    irepositoryidentitycontainer.GetByCondition(p => p.Id == conid,p=>true).SingleOrDefault();
            }
            if (!string.IsNullOrEmpty(departmentname))
            {
                var conid = irepositorydepartment.GetByCondition(p => p.Name == departmentname, p => true).SingleOrDefault().Con_Id;
                identitycontainer =
                    irepositoryidentitycontainer.GetByCondition(p => p.Id == conid, p => true).SingleOrDefault();
            }
            if (!string.IsNullOrEmpty(postname))
            {
                var conid = irepositorypost.GetByCondition(p => p.Name == postname, p => true).SingleOrDefault().Con_Id;
                identitycontainer =
                    irepositoryidentitycontainer.GetByCondition(p => p.Id == conid, p => true).SingleOrDefault();
            }

            if (!string.IsNullOrEmpty(rolename))
            {
                var conid = irepositoryrole.GetByCondition(p => p.Name== rolename, p => true).SingleOrDefault().Con_Id;
                identitycontainer =
                    irepositoryidentitycontainer.GetByCondition(p => p.Id == conid, p => true).SingleOrDefault();
            }

            if (!string.IsNullOrEmpty(objectname))
            {
                var objid = irepositoryobject.GetByCondition(p => p.Name == objectname, p => true).SingleOrDefault().Obj_Id;
                objectcontainer =
                    irepositoryobjectcontainer.GetByCondition(p => p.Id == objid, p => true).SingleOrDefault();
            }

            if (!string.IsNullOrEmpty(objectsetname))
            {
                var objid = irepositoryobjectset.GetByCondition(p => p.Name == objectsetname, p => true).SingleOrDefault().Obj_Id;
                objectcontainer =
                    irepositoryobjectcontainer.GetByCondition(p => p.Id == objid, p => true).SingleOrDefault();
            }

            if (!string.IsNullOrEmpty(permissionname))
            {
                var perid = irepositorypermission.GetByCondition(p => p.Name == permissionname, p => true).SingleOrDefault().Per_Id;
                permissioncontainer =
                    irepositorypermissioncontainer.GetByCondition(p => p.Id == perid, p => true).SingleOrDefault();
            }

            if (!string.IsNullOrEmpty(permissionsetname))
            {
                var perid = irepositorypermissionset.GetByCondition(p => p.Name == permissionsetname, p => true).SingleOrDefault().Per_Id;
                permissioncontainer =
                    irepositorypermissioncontainer.GetByCondition(p => p.Id == perid, p => true).SingleOrDefault();
            }

            var permissionassign = new BAS_PermissionAssgin(irepositorypermissionassign);
            permissionassign.CreatePermissionAssign(identitycontainer, objectcontainer,
                permissioncontainer);
        }

        /// <summary>
        /// 通过凭据容器ID与对象容器ID获取对应的权限容器ID
        /// </summary>
        /// <param name="obj_id"></param>
        /// <param name="con_id"></param>
        /// <returns></returns>
        private List<Guid> GetPer_idByObjAndIdentityId(Guid obj_id,Guid con_id)
        {
            return irepositorypermissionassign.GetByCondition(p => p.BAS_ObejctContainer.Id == obj_id
            && p.BAS_IdentityContianer.Id == con_id, p => true).Select(p=>p.BAS_PermissionConatiner.Id).ToList();
        }

        /// <summary>
        /// 根据凭据容器ID与对象容器ID和操作获取对应的所有权限
        /// </summary>
        /// <param name="obj_id"></param>
        /// <param name="con_id"></param>
        /// <param name="operation"></param>
        /// <returns></returns>
        private List<BAS_Permission> GetPermissionRuleByObjAndIdentityId(Guid obj_id,Guid con_id,OperationType operation)
        {
            var perids = GetPer_idByObjAndIdentityId(obj_id, con_id);
            var permissions = new List<BAS_Permission>();
            foreach(var perid in perids)
            {
                var permission =
                    irepositorypermission.GetByCondition(p => p.Per_Id == perid && p.Operation == operation, p => true).SingleOrDefault();
                permissions.Add(permission);
            }
            return permissions;
        }

        /// <summary>
        /// 将权限中的Value装换成Lamda表达式
        /// </summary>
        /// <param name="perlist"></param>
        /// <returns></returns>
        private Expression<Func<TAggreateRoot,bool>> GetExpressionByPermisson(List<BAS_Permission> perlist)
        {
            if(perlist.Count==1)
            {
                List<Conditions> conditions = Utils.JsonDeserialize<List<Conditions>>(perlist[0].CodeValue);
                return WhereLamdaConverter.Where<TAggreateRoot>(conditions);
            }
            if(perlist.Count>1)
            {
                var express = WhereLamdaConverter.Where<TAggreateRoot>
                    (Utils.JsonDeserialize<List<Conditions>>(perlist[0].CodeValue));
                for(var i=1;i<perlist.Count;i++)
                {
                    express.Or(WhereLamdaConverter.Where<TAggreateRoot>
                    (Utils.JsonDeserialize<List<Conditions>>(perlist[i].CodeValue)));
                }
                return express;
            }
            //没有对权限做限制
            return p => true;
        }

        /// <summary>
        /// 将[ProductName,UnitPrice]转换成 new(ProductName,UnitPrice)
        /// </summary>
        /// <param name="perlist"></param>
        /// <returns></returns>
        private string GetSelectByPermission(List<BAS_Permission> perlist)
        {
            if(perlist .Count==1)
            {
                if(!string.IsNullOrEmpty(perlist[0].CodeProperty))
                {
                    var selectstring = "New" + perlist[0].CodeProperty.Replace("[", "(").Replace("]", ")");
                    return selectstring;
                }
                return null;
            }
            if(perlist.Count>1)
            {
                var start = perlist[0].CodeProperty.Substring(1, perlist[0].CodeProperty.Length - 2).Split(',');
                //包含元素的时候
                if(start.Any())
                {
                    for(int i=1;i<perlist.Count;i++)
                    {
                        var start1 = perlist[i].CodeProperty;
                        string[] startnew = start1.Substring(1, start1.Length - 2).Split(',');
                        start = start.Union(startnew).ToArray();
                    }
                    var starts = string.Join(",", start);
                    var selectstring = "New" + "(" + starts + ")";
                    return selectstring;
                }
                return null;
            }
            return null;
        }

        public Expression<Func<TAggreateRoot,bool>> GetPermissionLamda(out string selector,
            OperationType operation)
        {
            var objectfullname = typeof(TAggreateRoot).ToString();
            var objectcode = objectfullname.Substring(objectfullname.LastIndexOf(".") + 1);
            var obj_ids = new List<Guid>();
            var obj = new BAS_ObjectService(irepositoryobject, irepositoryobjectcontainer)
                .GetObjectByCode(objectcode);
            if(obj!=null)
            {
                var objisexists = new BAS_PermissionAssgin(irepositorypermissionassign)
                    .GetPermissionAssignObjectIsExists(obj.Obj_Id);
                if(objisexists)
                {
                    obj_ids.Add(obj.Obj_Id);
                }
            }

            var objsets = new BAS_ObjectSetService(irepositoryobjectset, irepositoryobject,
                irepositoryobjectcontainer, irepositoryooset)
                .GetObjectSetByObjectCode(objectcode);
            if(objsets!=null)
            {
                foreach(var objset  in objsets)
                {
                    var objisexists = new BAS_PermissionAssgin(irepositorypermissionassign)
                        .GetPermissionAssignObjectIsExists(objset.Obj_Id);
                    if(objisexists)
                    {
                        obj_ids.Add(objset.Obj_Id);
                    }
                }
            }

            if (obj_ids.Count < 1)
            {
                selector = null;
                return p => true;
            }

            var permissions = new List<BAS_Permission>();

            var con_idstrings = SessionHelper.Gets("UserConId");
            var con_ids = new List<Guid>();
            for(int i=0;i<con_idstrings.Count();i++)
            {
                con_ids.Add(Guid.Parse(con_idstrings[i]));
            }

            foreach(var obj_id in obj_ids)
            {
                foreach(var con_id in con_ids)
                {
                    var permissionlist = GetPermissionRuleByObjAndIdentityId(obj_id, con_id, operation);
                    permissions.AddRange(permissionlist);
                }
            }

            if(permissions.Count<1)
            {
                selector = null;
                return p => true;
            }

            selector = GetSelectByPermission(permissions);
            return GetExpressionByPermisson(permissions);

        }
    }

 扩展EF查询的方法:

 public static class DynamicQueryable
    {
        public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
        {
            return (IQueryable<T>)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<T> Select<T>(this IQueryable<T> source, string selector, params object[] values)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (selector == null) throw new ArgumentNullException("selector");
            var lambda = DynamicExpression.ParseLambda(source.ElementType, source.ElementType, selector, values);
            return source.Provider.CreateQuery<T>(
                Expression.Call(
                    typeof(Queryable), "Select",
                    new[] { source.ElementType, lambda.Body.Type },
                    source.Expression, Expression.Quote(lambda)));
        }


        /// <summary>
        /// 将Lamda排序表达式转换成可以使用字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="sortName"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string sortName, string sortOrder)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (sortName == null || sortName.Trim() == string.Empty)
            {
                return source;
            }
            var propertyName = sortName.Trim();
            var parameter = Expression.Parameter(source.ElementType, String.Empty);
            var property = Expression.Property(parameter, propertyName);
            var lambda = Expression.Lambda(property, parameter);
            var methodName = (sortOrder.Trim().ToUpper() == "ASC") ? "OrderBy" : "OrderByDescending";
            var methodCallExpression = Expression.Call(typeof(Queryable), methodName,
                                                new[] { source.ElementType, property.Type },
                                                source.Expression, Expression.Quote(lambda));
            return source.Provider.CreateQuery<T>(methodCallExpression);
        }

        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
        {
            return (IQueryable<T>)OrderBy((IQueryable)source, ordering, source.ElementType, values);
        }

        public static IQueryable OrderBy(this IQueryable source, string ordering, Type t, 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<DynamicOrdering> orderings = parser.ParseOrdering(t);
            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 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<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values)
        {
            return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);
        }

        public static Type CreateClass(params DynamicProperty[] properties)
        {
            return ClassFactory.Instance.GetDynamicClass(properties);
        }

        public static Type CreateClass(IEnumerable<DynamicProperty> properties)
        {
            return ClassFactory.Instance.GetDynamicClass(properties);
        }
    }

    internal class DynamicOrdering
    {
        public Expression Selector;
        public bool Ascending;
    }

    internal class Signature : IEquatable<Signature>
    {
        public DynamicProperty[] properties;
        public int hashCode;

        public Signature(IEnumerable<DynamicProperty> 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<Signature, Type> 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<Signature, Type>();
            rwLock = new ReaderWriterLock();
        }

        public Type GetDynamicClass(IEnumerable<DynamicProperty> 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<string, object> keywords;

        Dictionary<string, object> symbols;
        IDictionary<string, object> externals;
        Dictionary<Expression, string> 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<string, object>(StringComparer.OrdinalIgnoreCase);
            literals = new Dictionary<Expression, string>();
            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<string, object>)
                {
                    externals = (IDictionary<string, object>)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(resultType);
            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<DynamicOrdering> ParseOrdering(Type t)
        {
            List<DynamicOrdering> orderings = new List<DynamicOrdering>();
            while (true)
            {
                Expression expr = ParseExpression(t);
                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(Type t)
        {
            int errorPos = token.pos;
            Expression expr = ParseLogicalOr(t);
            if (token.id == TokenId.Question)
            {
                NextToken();
                Expression expr1 = ParseExpression(t);
                ValidateToken(TokenId.Colon, Res.ColonExpected);
                NextToken();
                Expression expr2 = ParseExpression(t);
                expr = GenerateConditional(expr, expr1, expr2, errorPos);
            }
            return expr;
        }

        // ||, or operator
        Expression ParseLogicalOr(Type t)
        {
            Expression left = ParseLogicalAnd(t);
            while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
            {
                Token op = token;
                NextToken();
                Expression right = ParseLogicalAnd(t);
                CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
                left = Expression.OrElse(left, right);
            }
            return left;
        }

        // &&, and operator
        Expression ParseLogicalAnd(Type t)
        {
            Expression left = ParseComparison(t);
            while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
            {
                Token op = token;
                NextToken();
                Expression right = ParseComparison(t);
                CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
                left = Expression.AndAlso(left, right);
            }
            return left;
        }

        // =, ==, !=, <>, >, >=, <, <= operators
        Expression ParseComparison(Type t)
        {
            Expression left = ParseAdditive(t);
            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(t);
                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(Type t)
        {
            Expression left = ParseMultiplicative(t);
            while (token.id == TokenId.Plus || token.id == TokenId.Minus ||
                token.id == TokenId.Amphersand)
            {
                Token op = token;
                NextToken();
                Expression right = ParseMultiplicative(t);
                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(Type t)
        {
            Expression left = ParseUnary(t);
            while (token.id == TokenId.Asterisk || token.id == TokenId.Slash ||
                token.id == TokenId.Percent || TokenIdentifierIs("mod"))
            {
                Token op = token;
                NextToken();
                Expression right = ParseUnary(t);
                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(Type t)
        {
            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(t);
                }
                Expression expr = ParseUnary(t);
                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(t);
        }

        Expression ParsePrimary(Type t)
        {
            Expression expr = ParsePrimaryStart(t);
            while (true)
            {
                if (token.id == TokenId.Dot)
                {
                    NextToken();
                    expr = ParseMemberAccess(null, expr);
                }
                else if (token.id == TokenId.OpenBracket)
                {
                    expr = ParseElementAccess(expr, t);
                }
                else
                {
                    break;
                }
            }
            return expr;
        }

        Expression ParsePrimaryStart(Type t)
        {
            switch (token.id)
            {
                case TokenId.Identifier:
                    return ParseIdentifier(t);
                case TokenId.StringLiteral:
                    return ParseStringLiteral();
                case TokenId.IntegerLiteral:
                    return ParseIntegerLiteral();
                case TokenId.RealLiteral:
                    return ParseRealLiteral();
                case TokenId.OpenParen:
                    return ParseParenExpression(t);
                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(Type t)
        {
            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();
            Expression e = ParseExpression(t);
            ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected);
            NextToken();
            return e;
        }

        Expression ParseIdentifier(Type t)
        {
            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(t);
                if (value == (object)keywordNew) return ParseNew(t);
                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, t);
                }
                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(Type t)
        {
            int errorPos = token.pos;
            NextToken();
            Expression[] args = ParseArgumentList(t);
            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(Type t)
        {
            NextToken();
            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();
            List<DynamicProperty> properties = new List<DynamicProperty>();
            List<Expression> expressions = new List<Expression>();
            while (true)
            {
                int exprPos = token.pos;
                Expression expr = ParseExpression(t);
                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(t.GetProperty(properties[i].Name), expressions[i]);
            return Expression.MemberInit(Expression.New(t), bindings);
        }

        Expression ParseLambdaInvocation(LambdaExpression lambda, Type t)
        {
            int errorPos = token.pos;
            NextToken();
            Expression[] args = ParseArgumentList(t);
            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(type);
                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(type);
                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(elementType);
            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(Type t)
        {
            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();
            Expression[] args = token.id != TokenId.CloseParen ? ParseArguments(t) : new Expression[0];
            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
            NextToken();
            return args;
        }

        Expression[] ParseArguments(Type t)
        {
            List<Expression> argList = new List<Expression>();
            while (true)
            {
                argList.Add(ParseExpression(t));
                if (token.id != TokenId.Comma) break;
                NextToken();
            }
            return argList.ToArray();
        }

        Expression ParseElementAccess(Expression expr, Type t)
        {
            int errorPos = token.pos;
            ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);
            NextToken();
            Expression[] args = ParseArguments(t);
            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<MethodBase>(), 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<MethodBase> methods = members.
                        OfType<PropertyInfo>().
                        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<Type> SelfAndBaseTypes(Type type)
        {
            if (type.IsInterface)
            {
                List<Type> types = new List<Type>();
                AddInterface(types, type);
                return types;
            }
            return SelfAndBaseClasses(type);
        }

        static IEnumerable<Type> SelfAndBaseClasses(Type type)
        {
            while (type != null)
            {
                yield return type;
                type = type.BaseType;
            }
        }

        static void AddInterface(List<Type> 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<MethodBase> 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<string, object> CreateKeywords()
        {
            Dictionary<string, object> d = new Dictionary<string, object>(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";
    }

    public static class LinqSelect
    {
        /// <summary>
        /// 动态投影
        /// </summary>
        /// <typeparam name="T">实体类</typeparam>
        /// <param name="expression">源表达式(如Expression.Constant(DataContext.EntitySet<T>))</param>
        /// <param name="keys">关键字(数据字段field为键,显示名text为值</param>
        /// <param name="anonymousType">匿名类(如var anonymous = new { Name="", Age=0 }; </param>
        /// <returns></returns>
        public static Expression Select<T>(Expression expression, Dictionary<string, string> keys, Type anonymousType)
        {
            ParameterExpression paramTable = Expression.Parameter(typeof(T), "table");
            List<Expression> list = new List<Expression>();
            Expression[] paramFields = new Expression[keys.Count];
            Expression[] paramPropertys = new Expression[keys.Count];
            ParameterExpression[] paramTexts = new ParameterExpression[keys.Count];
            System.Reflection.MemberInfo[] memberInfos = new System.Reflection.MemberInfo[keys.Count];
            int i = 0;
            foreach (string key in keys.Keys)
            {
                paramFields[i] = null;
                paramTexts[i] = Expression.Parameter(anonymousType.GetProperty(keys[key]).PropertyType, keys[key]);
                System.Reflection.PropertyInfo propertyInfo = null;
                string[] strTemp = key.Split(new char[] { '.' });
                foreach (string str in strTemp)
                {
                    if (str == strTemp[0])
                    {
                        propertyInfo = typeof(T).GetProperty(str);
                        paramFields[i] = Expression.Property(paramTable, propertyInfo);
                    }
                    else
                    {
                        propertyInfo = propertyInfo.PropertyType.GetProperty(str);
                        paramFields[i] = Expression.Property(paramFields[i], propertyInfo);
                    }
                }
                list.Add(paramFields[i]);
                paramPropertys[i] = Expression.Equal(paramTexts[i], paramFields[i]);
                memberInfos[i] = anonymousType.GetMember(keys[key])[0];
                i++;
            }
            Expression paramConstrator = Expression.New(anonymousType.GetConstructors()[0], list, memberInfos);
            Expression lambdaExpression = Expression.Lambda(paramConstrator, paramTable);
            return Expression.Call(typeof(Queryable), "Select", new Type[] { typeof(T), anonymousType },
                expression, lambdaExpression);
        }
    }

 在ProductAppService中添加:

         /// <summary>
        /// 根据用户权限返回用户需要访问的信息
        /// </summary>
        /// <param name="conditions"></param>
        /// <param name="request"></param>
        /// <param name="totalcount"></param>
        /// <returns></returns>
        public List<Product> GetProductByCondition(List<Conditions> conditions,
            RequestPage request,out int totalcount)
        {
            string selector;
            var query = productrepository.GetByConditionPages(conditions, new PermissionAssignAppService<Product>()
                .GetPermissionLamda(out selector, OperationType.Read), request, out totalcount)
                .AsQueryable();
            if(selector !=null)
            {
                query = query.Select(selector);
            }

            return query.ToList();
        }

 在单元测试中模拟HttpContext请求上下文:

namespace DDD.Infrastructure
{
    public sealed class MySessionState : IHttpSessionState
    {
        const int MAX_TIMEOUT = 24 * 60;  // Timeout cannot exceed 24 hours.

        string pId;
        ISessionStateItemCollection pSessionItems;
        HttpStaticObjectsCollection pStaticObjects;
        int pTimeout;
        bool pNewSession;
        HttpCookieMode pCookieMode;
        SessionStateMode pMode;
        bool pAbandon;
        bool pIsReadonly;

        public MySessionState(string id,
        ISessionStateItemCollection sessionItems,
        HttpStaticObjectsCollection staticObjects,
        int timeout,
        bool newSession,
        HttpCookieMode cookieMode,
        SessionStateMode mode,
        bool isReadonly)
        {
            pId = id;
            pSessionItems = sessionItems;
            pStaticObjects = staticObjects;
            pTimeout = timeout;
            pNewSession = newSession;
            pCookieMode = cookieMode;
            pMode = mode;
            pIsReadonly = isReadonly;
        }
        public int Timeout
        {
            get { return pTimeout; }
            set
            {
                if (value <= 0)
                    throw new ArgumentException("Timeout value must be greater than zero.");

                if (value > MAX_TIMEOUT)
                    throw new ArgumentException("Timout cannot be greater than " + MAX_TIMEOUT.ToString());
                pTimeout = value;
            }
        }
        public string SessionID
        {
            get { return pId; }
        }
        public bool IsNewSession
        {
            get { return pNewSession; }
        }
        public SessionStateMode Mode
        {
            get { return pMode; }
        }
        public bool IsCookieless
        {
            get { return CookieMode == HttpCookieMode.UseUri; }
        }
        public HttpCookieMode CookieMode
        {
            get { return pCookieMode; }
        }
        // Abandon marks the session as abandoned. The IsAbandoned property is used by the
        // session state module to perform the abandon work during the ReleaseRequestState event.
        public void Abandon()
        {
            pAbandon = true;
        }
        public bool IsAbandoned
        {
            get { return pAbandon; }
        }
        // Session.LCID exists only to support legacy ASP compatibility. ASP.NET developers should use
        // Page.LCID instead.
        public int LCID
        {
            get { return Thread.CurrentThread.CurrentCulture.LCID; }
            set { Thread.CurrentThread.CurrentCulture = CultureInfo.ReadOnly(new CultureInfo(value)); }
        }
        // Session.CodePage exists only to support legacy ASP compatibility. ASP.NET developers should use
        // Response.ContentEncoding instead.
        public int CodePage
        {
            get
            {
                if (HttpContext.Current != null)
                    return HttpContext.Current.Response.ContentEncoding.CodePage;
                else
                    return Encoding.Default.CodePage;
            }
            set
            {
                if (HttpContext.Current != null)
                    HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding(value);
            }
        }
        public HttpStaticObjectsCollection StaticObjects
        {
            get { return pStaticObjects; }
        }
        public object this[string name]
        {
            get { return pSessionItems[name]; }
            set { pSessionItems[name] = value; }
        }
        public object this[int index]
        {
            get { return pSessionItems[index]; }
            set { pSessionItems[index] = value; }
        }
        public void Add(string name, object value)
        {
            pSessionItems[name] = value;
        }
        public void Remove(string name)
        {
            pSessionItems.Remove(name);
        }
        public void RemoveAt(int index)
        {
            pSessionItems.RemoveAt(index);
        }
        public void Clear()
        {
            pSessionItems.Clear();
        }
        public void RemoveAll()
        {
            Clear();
        }
        public int Count
        {
            get { return pSessionItems.Count; }
        }
        public NameObjectCollectionBase.KeysCollection Keys
        {
            get { return pSessionItems.Keys; }
        }
        public IEnumerator GetEnumerator()
        {
            return pSessionItems.GetEnumerator();
        }
        public void CopyTo(Array items, int index)
        {
            foreach (object o in items)
                items.SetValue(o, index++);
        }
        public object SyncRoot
        {
            get { return this; }
        }
        public bool IsReadOnly
        {
            get { return pIsReadonly; }
        }
        public bool IsSynchronized
        {
            get { return false; }
        }
    }
}

public static class MockHttpContext
{
    private const string ContextKeyAspSession = "AspSession";
    private static HttpContext context = null;
    public static void Init()
    {
        MySessionState myState = new MySessionState(Guid.NewGuid().ToString("N"),
        new SessionStateItemCollection(), new HttpStaticObjectsCollection(),
        5, true, HttpCookieMode.UseUri, SessionStateMode.InProc, false);

        TextWriter tw = new StringWriter();
        // 这个地方是可以修改的,这是设置的Web路径的地方,但文件是可以不存在的
        HttpWorkerRequest wr = new SimpleWorkerRequest("/webapp", "c:\\inetpub\\wwwroot\\webapp\\", "default.aspx", "", tw);
        context = new HttpContext(wr);
        HttpSessionState state = Activator.CreateInstance(
        typeof(HttpSessionState),
        BindingFlags.Public | BindingFlags.NonPublic |
        BindingFlags.Instance | BindingFlags.CreateInstance,
        null,
        new object[] { myState },
        CultureInfo.CurrentCulture) as HttpSessionState;
        context.Items[ContextKeyAspSession] = state;
        HttpContext.Current = context;
    }
    public static HttpContext Context
    {
        get
        {
            return context;
        }
    }
}

 在UserAppService中新建用户登录的方法:

     /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="no"></param>
        /// <param name="password"></param>
        public void UserLogin(string no,string password)
        {
            bas_userservice.UserLogin(no, password);
        }

 PermissionAssignAppService服务类:

 public class PermissionAssignAppService<TAggreateRoot> where TAggreateRoot :class,
        IAggreateRoot
    {
        IRepositoryContext context = ServiecLocator.Instance.GetService(typeof(IRepositoryContext))
       as IRepositoryContext;
        IRepository<BAS_PermissionAssgin> permissionassignrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_PermissionAssgin>))
            as IRepository<BAS_PermissionAssgin>;
        IRepository<BAS_IdentityContianer> identitycontainerrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_IdentityContianer>))
    as IRepository<BAS_IdentityContianer>;
        IRepository<BAS_ObejctContainer> objectcontainerrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_ObejctContainer>))
as IRepository<BAS_ObejctContainer>;
        IRepository<BAS_PermissionConatiner> permissioncontainerrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_PermissionConatiner>))
as IRepository<BAS_PermissionConatiner>;
        IRepository<BAS_User> userrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_User>))
as IRepository<BAS_User>;
        IRepository<BAS_Department> departmentrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_Department>))
as IRepository<BAS_Department>;
        IRepository<BAS_Post> postrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_Post>))
as IRepository<BAS_Post>;
        IRepository<BAS_Role> rolerepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_Role>))
as IRepository<BAS_Role>;

        IRepository<BAS_Obejct> objectrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_Obejct>))
as IRepository<BAS_Obejct>;
        IRepository<BAS_ObjectSet> objectsetrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_ObjectSet>))
as IRepository<BAS_ObjectSet>;
        IRepository<BAS_Permission> permissionrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_Permission>))
as IRepository<BAS_Permission>;

        IRepository<BAS_PermissionSet> permissionsetrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_PermissionSet>))
as IRepository<BAS_PermissionSet>;

        IRepository<BAS_OOSet> oosetrepository = ServiecLocator.Instance.GetService(typeof(IRepository<BAS_OOSet>))
as IRepository<BAS_OOSet>;
        BAS_PermissionAssignService<TAggreateRoot> bas_permissionservice;

        public PermissionAssignAppService()
        {
            bas_permissionservice =
                new BAS_PermissionAssignService<TAggreateRoot>(permissionassignrepository,
                identitycontainerrepository, objectcontainerrepository, permissioncontainerrepository,
                userrepository, departmentrepository, postrepository, rolerepository, objectrepository,
                objectsetrepository, permissionrepository, permissionsetrepository, oosetrepository);
        }

        /// <summary>
        /// 角色分配创建
        /// </summary>
        /// <param name="userno"></param>
        /// <param name="departmentname"></param>
        /// <param name="postname"></param>
        /// <param name="rolename"></param>
        /// <param name="objectname"></param>
        /// <param name="objectsetname"></param>
        /// <param name="permissionname"></param>
        /// <param name="permissionsetname"></param>
        public void CreatePermissionAssgin(string userno,string departmentname,string postname,
            string rolename,string objectname,string objectsetname,string permissionname,
            string permissionsetname)
        {
            bas_permissionservice.CreatePermissionAssgin(userno, departmentname, postname,
                rolename, objectname, objectsetname, permissionname, permissionsetname);
            context.Commit();
        }

        /// <summary>
        /// 查找权限,返回lamda表达式
        /// </summary>
        /// <param name="selector"></param>
        /// <param name="operation"></param>
        /// <returns></returns>
        public Expression<Func<TAggreateRoot,bool>> GetPermissionLamda(out string selector,
            OperationType operation)
        {
            return bas_permissionservice.GetPermissionLamda(out selector, operation);
        }

    }

 测试代码:

        [TestMethod]
        public void CreatePermissionAssign()
        {
            var permissionassignservice =
                new PermissionAssignAppService<Product>();
            permissionassignservice.CreatePermissionAssgin("10", null, null, null, "产品对象",
                null, "产品信息权限", null);

        }

        [TestMethod]
        public void TestProductAccess()
        {
            MockHttpContext.Init();
            int i;
            UserAppService userservice =
                new UserAppService();
            userservice.UserLogin("10", "pass");

            var fields = new string[1];
            fields[0] = "ProductName";

            var operators = new string[1];
            operators[0] = "Equal";

            var values = new string[1];
            values[0] = "P3";

            var relations = new string[1];
            relations[0] = "And";

            ProductAppService productservice =
                new ProductAppService();
            var pq = new RequestPage(1, 1, "ProductName", "desc");

            Assert.AreEqual(1, productservice.GetProductByCondition(Conditions.BuildConditions(fields, operators, values, relations), pq, out i).Count);

            Assert.IsNull(productservice.GetProductByCondition(Conditions.BuildConditions(fields, operators, values, relations), pq, out i)[0].Color);
            
        }

 

posted @ 2017-11-21 22:43  石shi  阅读(1027)  评论(0编辑  收藏  举报