Sto cercando di scrivere un ExpressionVisitor per avvolgere le mie espressioni LINQ su oggetto per rendere automaticamente i loro confronti tra maiuscole e minuscole senza distinzione tra maiuscole e minuscole, proprio come sarebbero in LINQ-to-entity.stringa senza confronti tra maiuscole e minuscole confronta nell'espressione LINQ
EDIT: VOGLIO SICURAMENTE utilizzare un ExpressionVisitor anziché applicare semplicemente un'estensione personalizzata o qualcosa alla mia espressione quando viene creato per un motivo importante: l'espressione passata al mio ExpressionVisitor viene generata dall'API Web ASP.Net Livello ODATA, quindi non ho il controllo sul modo in cui viene generato (cioè non riesco a scrivere in minuscolo la stringa che sta cercando eccetto all'interno di questo ExpressionVisitor).
deve supportare LINQ alle entità. Non solo estensione.
Ecco quello che ho finora. Cerca una chiamata a "Contains" su una stringa e quindi chiama ToLower su qualsiasi accesso membro all'interno di quella espressione.
Tuttavia, non funziona. Se visualizzo le espressioni dopo le mie modifiche, mi sembra corretto, quindi non sono sicuro di cosa potrei fare male.
public class CaseInsensitiveExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (insideContains)
{
if (node.Type == typeof (String))
{
var methodInfo = typeof (String).GetMethod("ToLower", new Type[] {});
var expression = Expression.Call(node, methodInfo);
return expression;
}
}
return base.VisitMember(node);
}
private Boolean insideContains = false;
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == "Contains")
{
if (insideContains) throw new NotSupportedException();
insideContains = true;
var result = base.VisitMethodCall(node);
insideContains = false;
return result;
}
return base.VisitMethodCall(node);
}
Se ho impostato un punto di interruzione sulla linea di "espressione tornare" nel metodo VisitMember e poi fare un "ToString" sul "nodo" e variabili "espressione", il punto di rottura viene colpito due volte, e qui sta ciò che i due insiemi di valori sono:
primo colpo:
node.ToString()
"$it.LastName"
expression.ToString()
"$it.LastName.ToLower()"
secondo colpo:
node.ToString()
"value(System.Web.Http.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty"
expression.ToString()
"value(System.Web.Http.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty.ToLower()"
Non ne so abbastanza delle espressioni per capire cosa sto facendo male a questo punto. Qualche idea?
'string.Equals (stringa1, stringa2, StringComparison.InvariantCultureIgnoreCase)'? – Corak
Evita 'ToLower' per il confronto tra stringhe in quanto è più probabile che si verifichi un errore ([Test Turchia] (http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html)). O utilizzare maiuscole o preferibilmente, come suggerito da Corak, String.Equals. – keyboardP
Questo non funzionerà nel mio caso. Innanzitutto, non ho il controllo su Expression, poiché viene generato automaticamente dall'API Web ASP.Net. In secondo luogo, voglio qualcosa che posso usare genericamente per concludere un'istruzione LINQ e che funzionerà sia con LINQ-to-entity che con LINQ-to-objects. –