2009-04-15 16 views
5

Chciałbym wiedzieć, czy możliwe jest użycie wyrażenia jako zmiennej/parametru w języku C#. Chciałbym zrobić coś takiego:C#: Czy istnieje sposób użycia wyrażeń jako zmiennej/parametru?

int x = 0; 
public void g() 
{ 
    bool greaterThan = f("x>2"); 
    bool lessThan = f("x<2"); 
} 
public bool f(Expression expression) 
{ 
    if(expression) 
     return true; 
    else 
     return false; 
} 

Oto co nie chcę zrobić:

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(x, '<', 2); 
} 

public bool f(int x, char c, int y) 
{ 
    if(c == '<') 
     return x < y; 
    if(c == '>') 
     return x > y; 
} 

Naprawdę co mi chodzi to sposób poruszania się za pomocą przełącznika lub seria instrukcji if dla każdego z: <> < => = ==! =. Czy jest jakiś sposób na zrobienie tego?

Edytuj: Załóżmy, że wyrażenie jest łańcuchem, np. "X < 2". Czy istnieje sposób, aby przejść od napisu do predykatu bez użycia serii instrukcji if na warunek?

Odpowiedz

11

Jest to bardzo możliwe, ale nie w dokładnej składni.

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(i => i > 2, x); 
    bool lessThan = f(i => i < 2, x); 
} 
public bool f(Func<int,bool> expression, int value) 
{ 
    return expression(value); 
} 

Właściwie to powinno być bliższe temu, co chcesz.

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(() => x > 2); 
    bool lessThan = f(() => x < 2); 
} 
public bool f(Func<bool> expression) 
{ 
    return expression(); 
} 

Odpowiedz Edycja

Jeśli chcesz być w stanie powiedzieć f("x < 2"), to będzie prawie niemożliwe. Ignorując parsowanie go (co może stać się nieprzyjemnym), musisz uchwycić wartość x, ale jest to tylko znak dla f, co sprawia, że ​​jest prawie niemożliwe.

+0

Cool. Edytowałem moje pytanie nieco w następujący sposób: Załóżmy, że wyrażenie jest ciągiem, np. "X <2". Czy istnieje sposób przejścia od napisu do predykatu bez użycia serii instrukcji if na tej postaci? –

+1

Jeśli jest to ciąg znaków, nie będzie łatwej i szybkiej odpowiedzi. Ale jeśli chcesz napisać f (x> 2), to po prostu spraw, aby f wziął parametr boolowski. – Samuel

+0

Drats, ok. Dzięki za odpowiedzi. –

9

Jeśli naprawdę chcesz, aby przejść wokół kodu dla tego, chcesz orzecznika:

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(i => i>2, x); 
    bool lessThan = f(i => i<2, x); 
} 
public bool f(Predicate<int> expression, int value) 
{ 
    return expression(value); 
} 

W przeciwnym razie, jeśli po prostu zastąpić bool dla Expression w pierwszym przykładzie Twój kod będzie kompilować dobrze:

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(x>2); 
    bool lessThan = f(x<2); 
} 
public bool f(bool expression) 
{ 
    if(expression) 
     return true; 
    else 
     return false; 
} 
+0

Wow, że downwote jest całkowicie nie na miejscu. Ta odpowiedź jest poprawna i bardziej zgodna z tym, czego poszukiwał pytający pod względem składni. – Samuel

+0

Miałem symbol zastępczy, który był tylko pierwszym zdaniem, zabrał mnie zbyt długo, aby go odtworzyć. –

+0

W rzeczywistości nie można po prostu wywołać funkcji expression(). Musisz podać w int. – Samuel

7

chyba że jestem brakuje czegoś ... dlaczego nie można po prostu zrobić:

bool greaterThan = x > 5; 
bool lessThan = x < 5; 

logiczny porównania już jest wyrazem ...

Edit:

Więc dla swojej funkcji, po prostu zdać bool:

public void f(bool expression) 
{ 
    // expression is either true or false... 
} 

f(x<5); // called like this 
+0

Główna różnica między Twoją odpowiedzią a innymi odpowiedziami w tym wątku to _when_ wykonanie porównania. Twój kod działa natychmiast, drugi kod działa tylko po wywołaniu 'expression'. Może to być przydatne, jeśli nie zawsze musisz wiedzieć, że 'greaterThan' i' x' są drogie do obliczenia. –

+0

Oznacza to, że 'x' jest wywołaniem funkcji lub innym wyrażeniem" opóźnionym ". –

+0

Dzięki za wyjaśnienie, nie mam możliwości korzystania z .NET 3.0, więc nie jestem obeznany z wyrażeniami lambda, ponieważ powinienem być –

0

Edycja: Załóżmy, że wyrażenie jest ciąg znaków, np. "x < 2". Czy istnieje sposób, aby przejść od napisu do predykatu bez użycia serii instrukcji if na warunek?

Istnieje kilka sztuczek, za pomocą których można zamienić łańcuchy w kod w .Net: CodeDom, Reflection.Emit, a nawet skryptowanie kompilatora w powłoce. Jednak żadna z nich nie jest tak prosta jak szybkie języki skryptowe. Zazwyczaj jest to źle widoczne w .Net, chyba że naprawdę wiesz, co robisz.

Zamiast tego.Net zapewnia przestrzeń nazw System.Addin jako bezpieczniejszy sposób na dodawanie rozszerzeń użytkownika do aplikacji.

2

Edytuj: Załóżmy, że wyrażenie jest łańcuchem, np. "X < 2". Czy istnieje sposób, aby przejść od napisu do predykatu bez użycia serii instrukcji if na warunek?

Jak niektórzy już wspomnieli; jeśli chcesz móc użyć łańcucha, potrzebujesz analizy. Naprawdę nie chcesz pisać własnego parsera C#, na szczęście niektórzy ludzie w Microsoft już to zrobili z Dynamic LINQ.

Oto rozwiązanie konkretnego pytania:

public void g() 
{ 
    int x = 0; 

    bool greaterThan = f("x > 2", x); 
    bool lessThan = f("x < 2", x); 
} 

public bool f(string expression, int x) 
{ 
    ParameterExpression xExpr = Expression.Parameter(typeof(int), "x"); 

    LambdaExpression e = DynamicExpression.ParseLambda(
     new ParameterExpression[] { xExpr }, typeof(bool), expression); 

    return (bool)e.Compile().DynamicInvoke(x); 
} 

Teraz, oczywiście, będzie wysadzić na najmniejszym typo w ciąg. Naprawdę musisz zastanowić się, czy faktycznie tego potrzebujesz. Ale jeśli naprawdę, możesz użyć metody DynamicExpression.ParseLambda, aby parsować ciągi znaków w LambdaExpression s.

+0

Naprawdę nie muszę tego robić, ale to jest niesamowite. Wypróbuję to. –

Powiązane problemy