Autor Beitrag
Cäptin Pommes
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Fr 07.09.12 16:21 
hallo leutz,

für meine WindowsPhone app habe ich eine eigenes Event geschrieben und es funktioniert auch! Jedoch versteh ich wenn ich ehrlich bin nicht wieso^^ und das kann nich das ziel sein dacht ich mir!
Durch mehrere Beispiel codes habe ich mir dann irgentwann das event zusammen gezimmert.
hier erstmal der code wo ich das event anwende:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
public delegate void EventHandler(object sender, LoginEventArgs e);
        public event EventHandler LoggedIn;

        protected virtual void OnLoggedIn(LoginEventArgs e)
        {
            EventHandler LoggedInEvent = LoggedIn;
            if (LoggedInEvent != null)
            { LoggedInEvent(this, e); }
        }

        public void Login(Dictionary<string,object> data)
        {
            PostClient pC = new PostClient(data);
            pC.DownloadStringCompleted += new PostClient.DownloadStringCompletedHandler(pC_DownloadStringCompleted);
            pC.DownloadStringAsync(new Uri(UrlStringRes.api, UriKind.Absolute));
        }

        void pC_DownloadStringCompleted(object sender, WindowsPhonePostClient.DownloadStringCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                XDocument doc = XDocument.Parse(e.Result);
                User.UserId = (string)doc.Element("user").Element("id");
                User.UserName = (string)doc.Element("user").Element("username");
                User.UserEmail = (string)doc.Element("user").Element("mail");
                User.Portal = (string)doc.Element("user").Element("portal");
                User.UserStatus = (string)doc.Element("user").Element("status");
                User.Active = (string)doc.Element("user").Element("isActive");
                OnLoggedIn(new LoginEventArgs(true));
            }
            else
            { OnLoggedIn(new LoginEventArgs(false)); }
        }
    }

    public class LoginEventArgs : EventArgs
    {
        public readonly bool isSuccessful;

        public LoginEventArgs(bool isSuccessful)
        { this.isSuccessful = isSuccessful; }
    }


besonders die OnLoggedIn methode versteh ich nich wirklich ...
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
protected virtual void OnLoggedIn(LoginEventArgs e)
        {
            EventHandler LoggedInEvent = LoggedIn;
            if (LoggedInEvent != null)
            { LoggedInEvent(this, e); }
        }

kann ich scheinbar auch problem los durch
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
protected virtual void OnLoggedIn(LoginEventArgs e)
        {
            //EventHandler LoggedInEvent = LoggedIn;
            if (LoggedIn != null)
            { LoggedIn(this, e); }
        }

ersetzen.
Wäre toll wenn mir jemand meinen eigenen code erklären kann :D
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 07.09.12 16:33 
Das kopieren des EventHandlers ist zum Schutz in Multithread Umgebungen. Erst den Multicast Event in eine neue Variable kopieren sorgt dafür das der sich nicht mehr ändert wenn ein anderer Thread einen weiteren delegaten an den originalen Multicastdelegaten anhängt oder schlimmer den letzten Delegaten entfernt. in deiner ~scheinbaren~ problemlosen Lösung könnte zwischen dem Test auf Null und dem Auslösen des delegaten ein anderer Thread den letzten delegaten abgehängt haben. Damit bekommst du dann doch eine NullReferenceException obwohl du auf null testest.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Fr 07.09.12 17:17 
du meinst wenn 2 threads übder das gleiche objekt darauf zugreifen? oder wie? nee ich verstehs immer noch noch so wirklich :/
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 07.09.12 17:38 
Ich versuchs nochmal mit etwas anderen Worten ;)

Dein Object veröffentlicht das Event. Beliebige andere Objekte können sich an den Event dieses Objekts dann registrieren. Diese anderen Objekte müssen nicht zwingend zum selben Thread gehören. Während dein Objekt also zum Beispiel gerade den Event werfen will, in deiner OnLoggedIn Methode, könnte sich gleichzeitig ein anderes Objekt in einem anderen Thread von deinem Event abmelden. Wenn der es schafft zwischen deinem Test auf null und dem eigentlich Aufruf zu kommen kann es knallen wenn kein registrierter Delegat übrig ist (weil LoggedIn dann null ist).

LoggedIn könnte sich also während der Auführung der OnLoggedIn Methode ändern. Um das zu verhindern macht man erst eine Kopie in eine lokale Variable, bei dir heißt die dann LoggedInEvent, um zu verhindern das sich diese ändern kann. Wenn sich LoggedIn tatsächlich ändert bleibt ja LoggedInEvent unberührt weil es eine Kopie ist und keine Referenz auf das gleiche Objekt ist. Damit wäre dieser Event dann Threadsafe.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Fr 07.09.12 18:19 
OK, ich glaub ich weis jetzt was du meinst...
Aber wenn ich 2 Objekte habe hängen doch deren die Events nich zusammen o.O
Oder meinst du was anderes?
kannst du mir das vielleicht in ein Stück Code geben?
Dann versteh ich glaub ich besser wie genau du das meinst :)
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 07.09.12 18:39 
Zitat:
Aber wenn ich 2 Objekte habe hängen doch deren die Events nich zusammen o.O


Nein. Du hast nur ein Objekt mit einen Event. An dem Event können aber beliebig viele andere Objekte aus beliebigen anderen Threads dranhängen und horchen.
Dein Aufruf von LoggedIn(this, e) kann theoretisch zu tausenden Methodenaufrufen in anderen Objekten, die alle deinen Event registriert, haben führen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
meinObjekt.LoggedIn += Objekt1.LoggedInEventHandler; 
meinObjekt.LoggedIn += Objekt2.LoggedInEventHandler;
meinObjekt.LoggedIn += Objekt3.LoggedInEventHandler;
meinObjekt.LoggedIn += Objekt4.LoggedInEventHandler;

... 
und wieder abmelden

meinObjekt.LoggedIn -= Objekt1.LoggedInEventHandler; 
meinObjekt.LoggedIn -= Objekt2.LoggedInEventHandler;
meinObjekt.LoggedIn -= Objekt3.LoggedInEventHandler;
meinObjekt.LoggedIn -= Objekt4.LoggedInEventHandler;


wen das jetzt nicht so einfach wie hier hintereinander steht sondern die auf deinen Event lauschenden anderen Objekte sich in anderen Thread ~beliebig~ an und abmelden hast du in der OnLoggedIn Methode ein potentielles Problem wenn du nicht eine lokale, dann unveränderliche Kopie, des Event Delegaten anlegst.

Für diesen Beitrag haben gedankt: Cäptin Pommes
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Fr 07.09.12 18:49 
OK danke :)