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); }
DDD领域模型之分配权限(十三)的更多相关文章
- DDD领域模型数据访问权限之权限(十二)
实现权限的领域对象:BAS_Permission public partial class BAS_Permission:AggreateRoot { private IRepository<B ...
- DDD领域模型数据访问权限之用户权限(十)
BAS_PRService岗位和角色服务: public class BAS_PRService { //岗位 private IRepository<BAS_Post> ireposit ...
- DDD领域模型数据访问权限(九)
权限分为:数据权限和功能权限 数据权限: 查询提供附加表达式的支持: //提供附加表达式的支持 List<TAggreateRoot> GetByCondition(Expression& ...
- [原]Jenkins(十一)---jenkins使用管理员admin创建用户和分配权限
/** * lihaibo * 文章内容都是根据自己工作情况实践得出. * 版权声明:本博客欢迎转发,但请保留原作者信息! http://www.cnblogs.com/horizonli/p/533 ...
- Linux 新建用户、用户组,给用户分配权限(chown、useradd、groupadd、userdel、usermod、passwd、groupdel)
Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号一方面可以帮助系统管理员对使用系统的用户进行 ...
- Vcenter server 5.5添加用户角色及分配权限
角色:各种角色定义了对此角色可操作细节的权限组合. 用户权限:用户权限是对ESXi 5.0中的对象实例(如ESXi 5.0主机,虚拟机,存储,网络等)进行权限的分配.通过在这些对象上绑定“用户+角色” ...
- linux 新建用户、用户组 以及为新用户分配权限
Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号 一方面可以帮助系统管理员对使用系统的用户进 ...
- asp.net core mvc权限控制:分配权限
前面的文章介绍了如何进行权限控制,即访问控制器或者方法的时候,要求当前用户必须具备特定的权限,但是如何在程序中进行权限的分配呢?下面就介绍下如何利用Microsoft.AspNetCore.Ident ...
- mysql创建用户并分配权限
添加新用户 允许本地 IP 访问 localhost, 127.0.0.1 create user 'test'@'localhost' identified by '123456'; 允许外网 IP ...
随机推荐
- C# 优化程序的四十七种方法
一.用属性代替可访问的字段 1..NET数据绑定只支持数据绑定,使用属性可以获得数据绑定的好处: 2.在属性的get和set访问器重可使用lock添加多线程的支持. 二.readonly(运行时常量) ...
- OpenGIS 介绍(转)
值此FOSS4G大会即将召开之日,最近我会在Blog上依次介绍一些OpenGIS标准.架构及用于实现的软件.一方面给初涉此行的朋友一个快速入门的概览,另一方面也是对我接触OpenGIS近一年来的总结. ...
- Java基础编程题——水仙花数
package com.yangzl.basic; /** * 题目:打印出所有的"水仙花数". * 所谓"水仙花数"是指一个三位数, * 其各位数字立方和等于 ...
- 下拉框combobox用法&级联餐单
如果下来内容不用后台取数据,直接写死的话不用url属性,直接用data即可: <input id="orderstate" name="orderstate&quo ...
- Database学习 - mysql 数据库 数据操作
mysql数据操作 查询语法 select * | field1,field1 ... from 表名 where 条件 group by 字段 having 筛选 order by 字段 limit ...
- CentOS 7以上版本Nginx开机自启
Nginx+Center OS 7.x 开机启动设置 centos 7以上是用Systemd进行系统初始化的,Systemd 是 Linux 系统中最新的初始化系统(init),它主要的设计目标是克服 ...
- 【windows核心编程】注入DLL时BUG排除与调试
DLL注入排除bug的思路步骤. 1.在VS中监视输入err,hr检查DLL是否注入成功 2.OD断点loadlibraryW,loadlibraryA是否已经注入成功,eax是否有值. 3.检查路径 ...
- XmlDocument根据节点的属性值获取节点
string targetParm = string.Format("STUDENTS/STUDENT[@NO='{0}']", targetValue);//生成目标获取节点的参 ...
- dns轮询
负载均衡最开始一步,利用它实现负载均衡集群的定位
- ORACLE 利用SCN恢复误delete的表
--kg是误删除的表 SQL> select count(*) from kg; COUNT(*) ---------- 820861 SQL> delete from kg; ...