Czy anonimowa metoda W C# może wywołać się sama?
Mam następujący kod:
class myClass
{
private delegate string myDelegate(Object bj);
protected void method()
{
myDelegate build = delegate(Object bj)
{
var letters= string.Empty;
if (someCondition)
return build(some_obj); //This line seems to choke the compiler
else string.Empty;
};
......
}
}
Czy jest inny sposób na skonfigurowanie anonimowej metody w C#, tak aby mogła ona wywoływać się sama?
6 answers
Możesz podzielić ją na dwa wyrażenia i użyć magii przechwyconych zmiennych, aby uzyskać efekt rekurencji:
myDelegate build = null;
build = delegate(Object bj)
{
var letters= string.Empty;
if (someCondition)
return build(some_obj);
else string.Empty;
};
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 19:17:07
Jeśli tworzysz funkcję rekurencyjną, zalecam unikanie anonimowych delegatów. Wystarczy utworzyć metodę i wywołać ją rekurencyjnie.
Metody anonimowe mają być anonimowe - nie powinieneś wywoływać ich po imieniu (nie-anonimowo).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 19:16:35
Anonymous Recursion in C # ma wspaniałą dyskusję na ten temat.
Rekurencja jest piękna, a lambdy są ostateczna abstrakcja. Ale jak można mogą być używane razem? Lambdy to funkcje anonimowe i rekurencja wymaga nazwisk...
Ponieważ to pojawiło się ponownie, oto przykład użycia kombinatora Y:
// This is the combinator
public static Func<A,R> Y<A,R>( Func<Func<A,R>, Func<A,R>> f )
{
Func<A,R> g = null;
g = f( a => g(a) );
return g;
}
Oto jego użycie do wywołania anonimowej, rekurencyjnej funkcji ...
Func<int,int> exp = Y<int,int>( e => x => ( x <=1 ) ? 1 : x * e( x - 1 ) );
Console.WriteLine( exp(5) );
Zauważysz że jeśli nie użyjesz y-combinatora i skonfigurujesz rekurencję tylko za pomocą delegata, nie otrzymasz poprawnej rekurencji. Na przykład ...
// This is BAD. Do not do this!
Func<int,int> badRec = null;
badRec = x => ( x <= 1 ) ? 1 : x * badRec( x - 1 );
Ale wszystko działa dobrze ...
Console.WriteLine( badRec(5) );
// Output
// 120
Ale spróbuj tego ...
Func<int,int> badRec = null;
badRec = x => ( x <= 1 ) ? 1 : x * badRec( x - 1 );
Func<int,int> badRecCopy = badRec;
badRec = x => x + 1;
Console.WriteLine( badRec(4) );
Console.WriteLine( badRecCopy(5) );
// Output
// 5
// 25
Co?!?
Widzisz, po linii badRec = x => x + 1;
, delegat, który masz, jest taki ...
badRecCopy = x => ( x <= 1 ) ? 1 : x * ( (x+1)-1 );
BadRec zwiększa wartość o 1, czego oczekujemy (4+1=5)
, ale badRecCopy zwraca teraz kwadrat wartości (5*( (5+1)-1 )
czego prawie na pewno się nie spodziewaliśmy.
Jeśli użyjesz y-combinatora, będzie działał zgodnie z oczekiwaniami ...
Func<int,int> goodRec = Y<int,int>( exp => x => ( x <=1 ) ? 1 : x * exp( x - 1 ) );
Func<int,int> goodRecCopy = goodRec;
I dostajesz to, czego oczekujesz.
goodRec = x => x + 1;
Console.WriteLine( goodRec(4) );
Console.WriteLine( goodRecCopy(5) );
// Output
// 5
// 120
Możesz przeczytać więcej o Y-combinator (link PDF).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-05 17:01:12
Nie można wywołać build
wewnątrz samej build
, ponieważ ciało anonimowej metody jest inicjalizacją samej zmiennej. Próbujesz użyć zmiennej przed jej zdefiniowaniem.
Nie polecam tego (ponieważ byłoby to dużo prostsze stworzyć tutaj prawdziwą metodę, która jest rekurencyjna) , ale jeśli jesteś zainteresowany, możesz przeczytać anonimową rekurencję w C#:
Rekurencja jest piękna, a lambdy są ostateczna abstrakcja. Ale jak można oni być używane razem? Lambdy to funkcje anonimowe i rekurencja wymaga nazwisk.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 19:16:56
Jeśli użyjesz Y , twoja funkcja stanie się parametrem samej funkcji, więc możesz ją wywołać rekurencyjnie:
class myClass {
private delegate string myDelegate(Object bj);
protected void method() {
myDelegate build = delegate(Object obj) {
// f is the function itself, which is passed into the function
return Functional.Y<Object, string>(f => bj => {
var letters = string.Empty;
if (someCondition)
return f(some_obj); // use f
else return string.Empty;
})(obj);
};
}
}
public static class Functional {
public delegate Func<A, R> Recursive<A, R>(Recursive<A, R> r);
public static Func<A, R> Y<A, R>(Func<Func<A, R>, Func<A, R>> f) {
Recursive<A, R> rec = r => a => f(r(r))(a);
return rec(rec);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-05 17:48:33
Jeśli docierasz do punktu rekurencyjnych metod anonimowych, możesz promować je jako normalną, prywatną metodę w swojej klasie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 19:17:22