Entwickler-Ecke

Basistechnologien - Statische Ereignisse erweitern


Delete - So 25.06.17 06:51
Titel: Statische Ereignisse erweitern
- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - So 25.06.17 10:26

Hallo,

das war mir schon bei deinem anderen Beitrag dazu aufgefallen: das ist kein gutes Design mit der statischen Methode MainClass.WndProc, da sich die beiden Klassen gegenseitig referenzieren.

Ich würde ein Event (bzw. Delegat) in WndClass deklarieren und mittels der MainClass daran binden (und diese kann dann wiederum eine virtuelle Methode aufrufen).
Hier (in Kürze) der Code dazu:

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:
public class MainClass
{
    public MainClass()
    {
        _wndClass = new WndClass();
        _wndClass.OnWndProc = OnWndProc;
    }

    protected void OnWndProc(ref Message m)
    {
        WndProc(ref m);
    }

    protected virtual void WndProc(ref Message m)
    {
        // ...
    }
}

class WndClass : NativeWindow 
{
    public delegate void WndProcDelegate(ref Message m);

    public WndProcDelegate OnWndProc;

    protected override void WndProc(ref Message m)
    {
        OnWndProc?.Invoke(ref m);

        base.WndProc(ref m);
    }
}

(falls dir ?. nichts sagt, dies ist ab C# 6 [https://msdn.microsoft.com/de-de/magazine/dn802602.aspx] möglich: Null-Conditional Operator - ansonsten einfach wie in deinen bisherigen OnDo...-Methoden aufrufen)

Und die MainClass-Ereignisse dann nicht-statisch deklarieren.


Delete - Mo 26.06.17 01:26

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Mo 26.06.17 09:04

Nur noch als Hinweis. Die C#-Version (also welchen Compiler du nutzt) hat nichts mit dem eingesetzten .NET-Framework zu tun...


Christian S. - Mo 26.06.17 09:10

Und noch ein Hinweis :D

Die korrekte Umsetzung des ?-Operators ist:

C#-Quelltext
1:
2:
3:
4:
5:
OnWndProc?.Invoke(ref m);
// wird zu
var tmp = OnWndProc;
if (tmp != null)
    tmp.Invoke(ref m);

Dann ist es auch thread-safe ;)


Delete - Mo 26.06.17 09:22

- Nachträglich durch die Entwickler-Ecke gelöscht -


Christian S. - Mo 26.06.17 09:33

Ohne die temporäre Variable könnte zwischen der if-Abfrage und dem Invoke ein anderer Thread das Feld nullen und es würde eine NullReferenceException geben. Durch die temporäre, lokale Variable kann ein anderer Thread nicht mehr zugreifen.


Th69 - Mo 26.06.17 09:34

Wenn genau zwischen den 2 Zeilen ein Threadwechsel stattfindet und dann die interne Eventmethoden-Liste geändert wird (im schlimmsten Fall das letzte Element gelöscht wird => Liste ist dann doch null => NullReferenceException).
Ob man das Event-De-/Abonnieren aber aus verschiedenen Threads überhaupt verwenden sollte, ist für mich eher designtechnisch zu hinterfragen.


Delete - Mo 26.06.17 12:06

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - Mo 26.06.17 20:10

Zitat:
Das gibt mir doch etwas zu denken, ob nicht auch andere Delphi und C# Projekte davon betroffen sind.


Das gilt eigentlich in jedem System. Sobald etwas prüfen und dann etwas mit dem geprüften tun 2 Dinge (nicht atomar) sind hat man ein potentielles Threading Problem.


Delete - Di 27.06.17 07:47

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - Di 27.06.17 09:38

Die einzige Referenz auf das neu erzeugte Array hat jetzt die Beispiel Methode insofern ist das potentiell ungefährlich.

Denn Zusammenhang zum vorher besprochenen verstehe ich aber nicht ganz :gruebel:


Delete - Di 27.06.17 09:55

- Nachträglich durch die Entwickler-Ecke gelöscht -