I am trying to get an expression tree to conditionally evaluate to a string.
Here is my code thus far:
IQueryable<Category> myCategories = DataUtil.Categories.AsQueryable();
ParameterExpression categoryParameterExpression = Expression.Parameter(typeof (Category), "category");
MemberExpression categoryNameMemberExpression = Expression.PropertyOrField(categoryParameterExpression, "CategoryName");
MemberExpression categoryNameLengthExpression = Expression.Property(categoryNameMemberExpression, typeof (string).GetProperty("Length"));
ConstantExpression constantLengthExpression = Expression.Constant(10, typeof (int));
BinaryExpression greaterThanLengthExpression = Expression.GreaterThan(categoryNameLengthExpression, constantLengthExpression);
var getNameInCapsMethod = typeof (Category).GetMethod("GetNameInCaps", BindingFlags.Instance | BindingFlags.Public);
MethodCallExpression getNameInCapsExpression = Expression.Call(categoryParameterExpression, getNameInCapsMethod, categoryNameMemberExpression);
ConditionalExpression ifGreaterThanLengthGetUpperNameExpression = Expression.IfThen(greaterThanLengthExpression, getNameInCapsExpression);
// I need something between the lambda and the ConditionalExpression to ensure that the void type is not returned?
var ifGreaterThanLengthGetUpperNameLambdaExpression = Expression.Lambda<Func<Category, string>>(ifGreaterThanLengthGetUpperNameExpression, new ParameterExpression[] { categoryParameterExpression });
foreach (var category in myCategories)
{
var upperName = ifGreaterThanLengthUpperLambda(category);
System.Windows.MessageBox.Show(upperName);
}
Here is the ArgumentException that is occuring at runtime:
An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll
Additional information: Expression of type 'System.Void' cannot be used for return type 'System.String'
I have figured out that ConditionalExpression is returning the void type for the "IfFalse" condition.
Here is the screenshot from my Expression Tree Visualizer:
I just want the string value. I realize that there is an Expression.IfThenElse on the ConditionalExpression type, but I'm not sure what to put in the Else expression. (I don't want to just pass back an empty string, if possible.) Is there a way for me to ensure that the condition is only evaluated when the preceding BinaryExpression evaluates to true? Regardless, how do I solve this problem?
It would probably be helpful to express more fully what you're really trying to achieve (essentially, what would the C# equivalent of your desired expression tree look like). At the moment, your expression tree looks roughly like the equivalent of this:
Func<Category, string> f = (category) => {
if (category.CategoryName.Length > 10) {
category.GetNameInCaps(category.CategoryName);
}
};
However, the C# compiler won't compile this, because you're not returning a string on any of the code paths, so it's no wonder that the expression tree isn't being compiled as you'd like. There are at least two problems:
Expression.Condition
instead of an Expression.IfThen
. This gives you the equivalent of the ... ? ... : ...
syntax in C#, which is an expression that can be used as the return value of your lambda. As a statement, an if (...) { }
block always has the type void
, as you've found (and this would be true even if you added an else
).null
or ""
), orIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With