Idę rzucić to tam jako głupie odpowiedź. Dla jasności: nie zrobiłbym tego i nie polecam nikomu tego robić. :)
Chciałem sprawdzić, czy można uzyskać składnię somelist.Where(!expr)
lub coś podobnego.
Cóż, udało mi się, a ja nienawidzę siebie.
var expr = N.egatable<MyClass>(x => x.Prop != 1);
somelist = someList.Where(!expr);
N.egatable
był tylko mały pomocnik składnia wygoda i w dużej mierze niepotrzebne (EDIT: chciał aby uniknąć konieczności jednoznacznie określić MyClass
lub w jakiś sposób dokonać konkretyzacji owijki obiektu ukrytego, ale nie potrafił się istnieje i że może ktoś będzie miał lepszy pomysł):
public static class N
{
public static Negator<T> egatable<T>(Func<T, bool> underlyingFunction)
{
return new Negator<T>(underlyingFunction);
}
}
Negator<T>
gdzie jest prawdziwy „magia” dzieje:
public class Negator<T>
{
private Func<T, bool> UnderlyingFunction;
public Negator(Func<T, bool> underlyingFunction)
{
this.UnderlyingFunction = underlyingFunction;
}
public static implicit operator Func<T, bool>(Negator<T> neg)
{
return v => neg.UnderlyingFunction(v);
}
public static Negator<T> operator !(Negator<T> neg)
{
return new Negator<T>(v => !neg.UnderlyingFunction(v));
}
}
Najpierw przeciążenie operatora !
realizuje funkcję negacji (tak jak w przypadku this answer), następnie niejawny operator konwersji na Func<T, bool>
pozwala przejść do metody rozszerzania Where
.
Być może bardzo głupie to można zachować przerzucanie go tam iz powrotem tak:
somelist = someList.Where(!!expr);
somelist = someList.Where(!!!expr);
somelist = someList.Where(!!!!expr);
somelist = someList.Where(!!!!!expr);
somelist = someList.Where(!!!!!!expr); //oh my what
Więc jeszcze raz ... proszę nie rób tego. :) Zdecydowanie trzymaj się właściwego/rozsądnego sposobu robienia rzeczy, jak w odpowiedzi Stevena.
EDYCJA: Oto implementacja za pomocą wyrażeń, które działają dokładnie w ten sam sposób pod względem użycia składni.Nie jestem pewien, czy jest to „poprawne”, a nie testowałem go przeciwko Entity Framework:
public class ExpressionNegator<T>
{
private Expression<Func<T, bool>> UnderlyingExpression;
public ExpressionNegator(Expression<Func<T, bool>> underlyingExpression)
{
this.UnderlyingExpression = underlyingExpression;
}
public static implicit operator Func<T, bool>(ExpressionNegator<T> neg)
{
return neg.UnderlyingExpression.Compile();
}
public static implicit operator Expression<Func<T, bool>>(ExpressionNegator<T> neg)
{
return neg.UnderlyingExpression;
}
public static ExpressionNegator<T> operator !(ExpressionNegator<T> neg)
{
var originalExpression = neg.UnderlyingExpression;
Expression<Func<T, bool>> negatedExpression = originalExpression.Update(
Expression.Not(originalExpression.Body),
originalExpression.Parameters);
return new ExpressionNegator<T>(negatedExpression);
}
}
Przepraszam cię torturować więcej, bo wiem, że to będzie prawdopodobnie jeść na ciebie, aż pojawi się ona pracować zbyt (byłem tam). Zastanawiam się, czy można go uruchomić z 'Wyrażeniem>' również, aby działało z dostawcami Linq2Entities, takimi jak Entity Framework. –
@ScottChamberlain: Prawdopodobnie mógłbym to zrobić za pomocą wyrażeń, ale nie wiem, czy byłoby to zgodne z kompatybilnym wykonaniem _runtime_ dla encji (przypuszczam, że to _mrok_, w sumie, jakie są dodatkowe negacje dla zapytania SQL?). Może w wolnym czasie dam mu szansę. –
Jeśli chcesz przekształcić lambdę w jej przeciwieństwo, możesz po prostu napisać, ze zmienną "Wyrażenie> originalLambda',' Wyrażenie > negatedLambda = originalLambda.Update (Expression.Not (originalLambda.Body), originalLambda .Parameters); ' –