Sto cercando di ottenere un albero di espressioni per valutare condizionalmente una stringa.
Ecco il mio codice finora:
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);
}
Ecco l'ArgumentException che si sta verificando in fase di runtime:
Si è verificata un'eccezione non gestita di tipo "System.ArgumentException" in System.Core.dll
Informazioni aggiuntive: non è possibile utilizzare l'espressione di tipo "System.Void" per il tipo restituito "System.String"
Ho capito che ConditionalExpression sta restituendo il tipo di vuoto per la condizione "IfFalse".
Ecco lo screenshot dal mio Visualizzatore dell'albero delle espressioni:
Voglio solo il valore della stringa. Mi rendo conto dell'esistenza di Expression.IfThenElse sul tipo ConditionalExpression, ma non sono sicuro di cosa inserire nell'espressione Else. (Non voglio solo restituire una stringa vuota, se possibile.) C'è un modo per assicurarmi che la condizione venga valutata solo quando la precedente Espressione Binario restituisce true? Indipendentemente da ciò, come posso risolvere questo problema?
Sarebbe probabilmente utile esprimere più pienamente quello che stai cercando di ottenere (in sostanza, quale sarebbe l'equivalente C # del tuo albero di espressione desiderato). Al momento, il tuo albero delle espressioni assomiglia all'incirca all'equivalente di questo:
Func<Category, string> f = (category) => {
if (category.CategoryName.Length > 10) {
category.GetNameInCaps(category.CategoryName);
}
};
Tuttavia, il compilatore C # non lo compilerà, perché non stai restituendo una stringa su nessuno dei percorsi del codice, quindi non c'è da meravigliarsi che l'albero delle espressioni non venga compilato come desideri. Ci sono almeno due problemi:
Expression.Condition
invece di Expression.IfThen
. Questo ti dà l'equivalente del ... ? ... : ...
sintassi in C #, che è un'espressione che può essere utilizzata come valore di ritorno del tuo lambda. Come una dichiarazione, un blocco if (...) { }
ha sempre il tipo void
, come hai trovato (e questo sarebbe vero anche se hai aggiunto un else
). null
o ""
), o