Reputation: 11990
In a C# project, I want to create a function that allows me to pass lambda expression which I can parse each expression into a PropertyInfo where I can extract the property name and the property value.
Here is a stripped down version of my code
public IEnumerable<Student> Make(IEnumerable<User> users, Expression<Func<User, dynamic>> primaryProperty, params Expression<Func<User, dynamic>>[] otherProperties)
{
var students = new List<Student>();
foreach(User user in users)
{
var student = new Student();
var mainProp = GetPropertyInfo(user, primaryProperty);
object mainValue = prop.GetValue(user, null);
// Do somthing with mainProp.Name...
// Do something with mainValue ...
foreach(Expression<Func<User, dynamic> exp in otherProperties ?? new Expression<Func<User, dynamic>>[] {})
{
var prop = GetPropertyInfo(user, exp);
object value = prop.GetValue(user, null);
// Set the property student property
// Do somthing with prop.Name...
// Do something with value...
}
students.Add(student);
}
return strudents;
}
private static PropertyInfo GetPropertyInfo<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
if (!(propertyLambda.Body is MemberExpression expression))
{
throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property.");
}
PropertyInfo propInfo = expression.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property.");
}
if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType))
{
throw new ArgumentException($"Expression '{propertyLambda}' refers to a property that is not from type {type}.");
}
return propInfo;
}
When I pass property of a primitive type to the function, the GetPropertyInfo
fails as propertyLambda.Body as MemberExpression expression
returns null.
From google, it seems that the cause of this issue is because I am using dynamic
as a return value to the function where it should be something like TProperty
instead. Here is a reference Expression.Body as MemberExpression returns null for primitive property
However, I am not sure how to rewrite my Make
method to use TProperty
instead of dynamic
every property can have a different type.
Question How can I pass multiple lambda expression to the Make
method then obtain the property info for each expression?
Upvotes: 1
Views: 159
Reputation: 156524
You should be fine to use object
instead of dynamic
in your expression types.
public IEnumerable<Student> Make(IEnumerable<User> users, Expression<Func<User, object>> primaryProperty, params Expression<Func<User, object>>[] otherProperties)
The thing to be aware of is that your expression body will most likely be wrapped in a Convert expression, representing the fact that your property is being implicitly cast as an object. So you'll probably need code something like this in your GetPropertyInfo method.
var expressionBody = propertyLambda.Body;
if (expressionBody is UnaryExpression expression && expression.NodeType == ExpressionType.Convert)
{
expressionBody = expression.Operand;
}
Upvotes: 1