Last active
September 29, 2021 10:21
-
-
Save mstrYoda/663789375b0df23e2662a53bebaf2c7c to your computer and use it in GitHub Desktop.
Creating dynamically select lambda methods using expressions with c#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SelectLambdaBuilder<T> | |
{ | |
private static Dictionary<Type, PropertyInfo[]> _typePropertyInfoMappings = new Dictionary<Type, PropertyInfo[]>(); | |
private readonly Type _typeOfBaseClass = typeof(T); | |
private Dictionary<string, List<string>> GetFieldMapping(string fields) | |
{ | |
if (string.IsNullOrEmpty(fields)) | |
{ | |
return null; | |
} | |
var selectedFieldsMap = new Dictionary<string, List<string>>(); | |
foreach (var s in fields.Split(',')) | |
{ | |
var nestedFields = s.Split('.').Select(f => f.Trim()).ToArray(); | |
var nestedValue = nestedFields.Length > 1 ? nestedFields[1] : null; | |
if (selectedFieldsMap.Keys.Any(key => key == nestedFields[0])) | |
{ | |
selectedFieldsMap[nestedFields[0]].Add(nestedValue); | |
} | |
else | |
{ | |
selectedFieldsMap.Add(nestedFields[0], new List<string> { nestedValue }); | |
} | |
} | |
return selectedFieldsMap; | |
} | |
public Func<T, T> CreateNewStatement(string fields) | |
{ | |
var selectFields = GetFieldMapping(fields); | |
if (selectFields == null) | |
{ | |
return s => s; | |
} | |
ParameterExpression xParameter = Expression.Parameter(_typeOfBaseClass, "s"); | |
NewExpression xNew = Expression.New(_typeOfBaseClass); | |
var shpNestedPropertyBindings = new List<MemberAssignment>(); | |
foreach (var keyValuePair in selectFields) | |
{ | |
PropertyInfo[] propertyInfos; | |
if (!_typePropertyInfoMappings.TryGetValue(_typeOfBaseClass, out propertyInfos)) | |
{ | |
var properties = _typeOfBaseClass.GetProperties(); | |
propertyInfos = properties; | |
_typePropertyInfoMappings.Add(_typeOfBaseClass, properties); | |
} | |
var propertyType = propertyInfos | |
.FirstOrDefault(p => p.Name.ToLowerInvariant().Equals(keyValuePair.Key.ToLowerInvariant())) | |
.PropertyType; | |
if (propertyType.IsClass) | |
{ | |
PropertyInfo objClassPropInfo = _typeOfBaseClass.GetProperty(keyValuePair.Key); | |
MemberExpression objNestedMemberExpression = Expression.Property(xParameter, objClassPropInfo); | |
NewExpression innerObjNew = Expression.New(propertyType); | |
var nestedBindings = keyValuePair.Value.Select(v => | |
{ | |
PropertyInfo nestedObjPropInfo = propertyType.GetProperty(v); | |
MemberExpression nestedOrigin2 = Expression.Property(objNestedMemberExpression, nestedObjPropInfo); | |
var binding2 = Expression.Bind(nestedObjPropInfo, nestedOrigin2); | |
return binding2; | |
}); | |
MemberInitExpression nestedInit = Expression.MemberInit(innerObjNew, nestedBindings); | |
shpNestedPropertyBindings.Add(Expression.Bind(objClassPropInfo, nestedInit)); | |
} | |
else | |
{ | |
Expression mbr = xParameter; | |
mbr = Expression.PropertyOrField(mbr, keyValuePair.Key); | |
PropertyInfo mi = _typeOfBaseClass.GetProperty( ((MemberExpression)mbr).Member.Name ); | |
var xOriginal = Expression.Property(xParameter, mi); | |
shpNestedPropertyBindings.Add(Expression.Bind(mi, xOriginal)); | |
} | |
} | |
var xInit = Expression.MemberInit(xNew, shpNestedPropertyBindings); | |
var lambda = Expression.Lambda<Func<T,T>>( xInit, xParameter ); | |
return lambda.Compile(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how can i use this?
var result = list.Select( CreateNewStatement( "Field1, Field2" ) );
???