/// <summary> /// Convert the string of the properties to a SelectEntry collection /// </summary> /// <param name="properties"></param> /// <param name="prefix"></param> /// <returns></returns> private List <SelectEntry> ParsePropertyNames(string properties, string prefix = "") { string pattern = @"((?<complex>[A-Za-z0-9]+)\[(?<props>[[A-Za-z0-9,]+)\]?)+|(?<simple>\w+)"; List <SelectEntry> ret = new List <SelectEntry>(); MatchCollection matches = Regex.Matches(properties.Replace(" ", ""), pattern); if (matches.Any()) { matches.ToList().ForEach(o => { if (!String.IsNullOrEmpty(o.Groups["simple"].Value)) { ret.Add(new SelectEntry() { Property = o.Value }); } else { SelectEntry entry = new SelectEntry() { Property = o.Groups["complex"].Value, Childs = ParsePropertyNames(o.Groups["props"].Value) }; ret.Add(entry); } }); } return(ret); }
public SelectEntry AddChildProperty(SelectEntry entry) { Childs.Add(entry); return(this); }
private IList <MemberAssignment> ProcessEntry(SelectEntry entry, ParameterExpression parameter, string suffix = "") { List <MemberAssignment> bindings = new List <MemberAssignment>(); Type type = parameter.Type; //process the sub properties if (entry.Childs.Count > 0) { PropertyInfo propertyInfo = Utils.GetPropertyInfo(parameter.Type, entry.Property); MemberExpression originalMember = Expression.Property(parameter, propertyInfo); Type childType = propertyInfo.PropertyType; ParameterExpression childParameter = Expression.Parameter(childType, entry.Property); List <MemberAssignment> subBindings = new List <MemberAssignment>(); var isCollection = Utils.IsEnumerable(childParameter); //The property is a Enumerable if (isCollection) { // Get the type of the child elements Type elementType = childType.GetGenericArguments()[0]; // Create an expression for the parameter ParameterExpression elementParameter = Expression.Parameter(elementType, entry.Property + ".Element"); foreach (SelectEntry e in entry.Childs) { subBindings.AddRange(ProcessEntry(e, elementParameter)); } // Convert the list to Queryable Expression asQueryable = Utils.AsQueryable(childParameter); //Expression to generate a new element of the list NewExpression newElementExpression = Expression.New(elementType); MemberInitExpression initElementExpression = Expression.MemberInit(newElementExpression, subBindings); //Iterate over the original elements (Queryable.Select) MethodCallExpression selectExpr = Expression.Call(typeof(Queryable), "Select", new[] { elementType, elementType }, asQueryable, MakeLambda(initElementExpression, elementParameter)); //Convert the result to list Expression toListCall = Expression.Call(typeof(Enumerable), "ToList", selectExpr.Type.GetGenericArguments(), selectExpr); // Check for null original collection (avoid null pointer) Expression notNullConditionExpression = Expression.NotEqual(childParameter, Expression.Constant(null, childParameter.Type)); Expression trueExpression = MakeLambda(Expression.Convert(toListCall, childParameter.Type), childParameter); Expression falseExpression = MakeLambda(Expression.Constant(null, childParameter.Type), childParameter); Expression notNullExpression = Expression.Condition(notNullConditionExpression, trueExpression, falseExpression); Expression notNullLambda = MakeLambda(Expression.Invoke(notNullExpression, originalMember), childParameter); //Invocate the null-check expression Expression invocation = Expression.Invoke(notNullLambda, originalMember); // Add the invocation to the bindings on the original element bindings.Add(Expression.Bind(propertyInfo, invocation)); } else { // Add the child entities to the initialization bindings of the object foreach (SelectEntry e in entry.Childs) { subBindings.AddRange(ProcessEntry(e, childParameter)); } // Add the lambda to the bindings of the property in the parent object bindings.Add(Expression.Bind(propertyInfo, CreateNewObject(childParameter, childType, subBindings, originalMember))); } } else { // Add the property to the init bindings bindings.Add(AssignProperty(parameter.Type, entry.Property, parameter)); } return(bindings); }