WPF, zdarzenia a funkcje anonimowe

0

Chciałem program który generował bym kod grafu, na podstawie rysunku zrobionego przez użytkownika. Program ma kilka stanów, dodawanie, rysowanie , oczekiwanie itd. Chciałem zamiast kilku metod w stylu lewy_klik_w_tło, prawy_kilk.. i tysiąca if'ów w każdej, mieć dużo malutkich metod i podmieniać je wraz ze zmianą stanu . Taki był plan... Kod w wersji v1 działa tak że nie ważne co będzie się działo ze zmienną _vertexClickHandler, choćby tam null był, to wykona się funkcja przechowywana przez _vertexClickHandler; w momencie internalizacji. Wersja z lambdą działa "normalnie" tylko nie mam pojęcia o co właciwie chodzi :? wytłumaczył by ktoś ta magie?

 
        private Action<object, MouseEventArgs> _vertexClickHandler;
        private void AddVertex(object sender, MouseEventArgs e)
        {
         // v1-nie działa
         // Vertex v = new Vertex( _vertexClickHandler));
         //v2 działa
           Vertex v = new Vertex( (x, y) => { _vertexClickHandler(x, y); }); 

           var pos = e.GetPosition(this.VertexLayer);
           v.Draw(pos.X, pos.Y);
        }
class Vertex()
{//(...)
        public Vertex( Action<object, MouseEventArgs> clickHandler)
        {
            this.Click = clickHandler;
            this._tb = new TextBox();
            this._body = new Ellipse();
            this._tb.PreviewMouseDown += SendClickToComposite;
            this._body.PreviewMouseDown += SendClickToComposite;
        }
        private void SendClickToComposite(object o, MouseEventArgs e)
        {
            this.Click(this, e);
        }
}
0

Na mój rozum Action to tylko ładnie zapisany wskaźnik do funkcji, a nie żaden obiekt i używając referencji do akcji tak na prawdę posługujemy się referencją do tej funkcji. Taki cukierek składniowy.. Znak ktoś jakieś źródła gdzie jest dokładnie wyśnione jak to działa?.

        public static Action _method=m1;
        static void Main(string[] args)
        {
            MyClass c1 = new MyClass(_method);
            MyClass c2 = new MyClass(() => { _method(); });
            MyClass c3 = new MyClass(new Action(() => { _method(); }));  
            MyClass2 sdClass = new MyClass2(_method);
            Console.WriteLine("Próba kontorlna");
            _method();
            c1.actn();
            c2.actn();
            c3.actn();
            sdClass.actn();
 // wynik :
//metoda 1
//metoda 1
//metoda 1
//metoda 1
//metoda 1
            _method = m2;
            Console.WriteLine("Zamina metody");
            _method();
            c1.actn();
            c2.actn();
            c3.actn();
            sdClass.actn();
 // wynik :
//metoda 2
//metoda 1
//metoda 2
//metoda 2
//metoda 1
            Console.ReadKey();
        }
        class MyClass
        {
            public Action actn { get; set; }
            public MyClass(Action action)
            {
                this.actn = action;
            }
        }
        class MyClass2
        {
            public Action actn { get; set; }
            public MyClass2(Action action)
            {
                this.actn = new Action(action);
            }
        }
        static void m1()
        {
            Console.WriteLine("metoda 1");
        }
        static void m2()
        {
            Console.WriteLine("metoda 2");;
        }
 
2

najprawdopodobniej chodzi ci o wyjasnienie jak dzialaja closures w c#, z tego co pamietam w c# in depth bylo to opisane w dosc prosty a zarazem wyczerpujacy sposob.
w sytuacji jesli w lambdzie (lub anonimowym delegacie) bedzie uzywana zmienna A ktora jest zdefiniowana w zewnetrznym zakresie to w chwili wywolania tejze lambdy, bedzie uzyty stan zmiennej A z momentu w ktorym lambda jest wywolywana a nie w ktorej byla definiowana, przykladowo:

var number = 1;
var write = new Action(() => Console.WriteLine(number));
number++;
write();//wypisuje 2

co sie dzieje pod spodem? kompilator dla twojej lambdy generuje dodatkowa strukture ktora trzyma referencje do 'przechwyconych' obiektow.
btw ten cukier skladniowy o ktorym mowisz to nie jest na wskazniki do funkcji a na 'pelnowartosciowe' obiekty, zwane delegatami (instancje klasy MulticastDelegate) ktore oprocz trzymania referencji do funkcji (niekoniecznie jednej) maja calkiem spora game utilsow https://msdn.microsoft.com/en-us/library/system.multicastdelegate(v=vs.110).aspx

1 użytkowników online, w tym zalogowanych: 0, gości: 1