-
Notifications
You must be signed in to change notification settings - Fork 7
Open
Description
// Following code will allow you to use your library with nested properties
// Hopefully I have everything included, let me know if I missed anything.
// Example - Would work with property "Claim.ClaimReason.ClaimReasonDescription"
`public static IQueryable<dynamic> SelectProperties<T>(this IQueryable<T> source, IEnumerable<String> propertyNames)
{
if (source == null) throw new ArgumentNullException("Source Object is NULL");
var sourceItem = Expression.Parameter(source.ElementType, "t");
var sourceProperties = propertyNames.Where(name => source.ElementType.HasProperty(name) == true).ToDictionary(name => name, name => source.ElementType.GetPropertyInfo(name));
var dynamicType = DynamicTypeBuilder.GetDynamicType(sourceProperties.Values.ToDictionary(f => f.Name, f => f.PropertyType), typeof(object), Type.EmptyTypes);
var bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, BuildMemberExpression(sourceProperties.FirstOrDefault(a => a.Value.Name == p.Name).Key, sourceItem))).OfType<MemberBinding>().ToList();
var selector = Expression.Lambda<Func<T, dynamic>>(Expression.MemberInit(Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem);
return source.Select(selector);
}
private static MemberExpression GetInitalMemberExpression(string v, ParameterExpression parameterExpression)
{
return Expression.Property(parameterExpression, v);
}
private static MemberExpression BuildMemberExpression(String selector, ParameterExpression expression, Int32 index = 0)
{
var segments = selector.Split((".").ToCharArray()).ToList();
MemberExpression memberExpression = GetInitalMemberExpression(segments[0], expression);
return BuildMemberExpression(segments, memberExpression, ++index);
}
private static MemberExpression BuildMemberExpression(List<String> segments, MemberExpression finalExpression, Int32 index = 0)
{
if (index >= segments.Count)
{
return finalExpression;
}
finalExpression = Expression.Property(finalExpression, segments[index]);
return BuildMemberExpression(segments, finalExpression, ++index);
}
public static Boolean HasProperty(this Type type, String name)
{
var parts = name.Split('.');
if (parts.Length == 1)
{
return type.GetProperty(name) == null ? false : true;
}
else
{
var part1 = parts[0];
var part2 = String.Join(".", parts.Where(a => a != part1));
var prop1 = type.GetProperty(part1);
if (prop1 == null) { return false; }
else { return prop1.PropertyType.HasProperty(part2); }
}
}
public static PropertyInfo GetPropertyInfo(this Type type, String name)
{
var parts = name.Split('.');
if (parts.Length == 1)
{
return type.GetProperty(name);
}
else
{
var part1 = parts[0];
var part2 = String.Join(".", parts.Where(a => a != part1));
var prop1 = type.GetProperty(part1);
if (prop1 == null) { return null; }
else { return prop1.PropertyType.GetPropertyInfo(part2); }
}
}
`
Metadata
Metadata
Assignees
Labels
No labels