2016-09-03 4 views
1

Ich versuche zu verstehen, wie die Kombination von Delegaten funktioniert. Im folgenden Code habe ich die übliche Implementierung von set (mit einer einfachen Zuweisung, unter Verwendung = Operator) in eine schlecht geformte (mit dem Operator +=) geändert.Wie wird die Delegataufrufliste erstellt?

So ist der folgende Code:

using System; 
using System.Linq; 

class Cooler 
{ 
    public void OnTemperatureChanged(float newTemperature) {} 
} 

class Heater 
{ 
    public void OnTemperatureChanged(float newTemperature) {} 
} 

public class Thermostat 
{ 
    private Action<float> _OnTemperatureChange; 

    public Action<float> OnTemperatureChange 
    { 
     get 
     { return _OnTemperatureChange; } 
     set 
     { 
      _OnTemperatureChange += value; // note the += 
     } 
    } 

    public void PrintRegistered() 
    { 
     if (OnTemperatureChange != null) 
     { 
      foreach (Delegate existingHandler in _OnTemperatureChange.GetInvocationList()) 
      { 
       Console.WriteLine(existingHandler.Target + "." + existingHandler.Method); 
      } 
     } 
    } 
} 

class Program 
{ 
    public static void Main() 
    { 
     Thermostat thermostat = new Thermostat(); 
     Heater heater = new Heater(); 
     Cooler cooler = new Cooler(); 

     thermostat.OnTemperatureChange += cooler.OnTemperatureChanged; 
     thermostat.OnTemperatureChange += heater.OnTemperatureChanged; 
     thermostat.PrintRegistered(); 
    } 
} 

Drucke:

Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 

Natürlich Wenn ich die set zu seiner üblichen Implementierung ändern zurück, werden wir eine einzige OnTemperatureChanged für Cooler sehen und Heater .

Ich würde gerne verstehen, warum die Einstellung der Delegierten auf diese Weise in dieser Form der Aufrufliste führte?

+0

Warum würden Sie hier keine Veranstaltung verwenden? Dies ist genau das Szenario, für das Ereignisse konzipiert sind. –

+0

Helter Skelter ist eine nette Episode. – usr

Antwort

1

+= für Delegierte Anrufe Delegate.Combine. thermostat.OnTemperatureChange += cooler.OnTemperatureChanged; ruft dies zweimal auf: Einmal in Main und einmal in set_OnTemperatureChange. Es ist also ein banaler Fehler, der die Nebenwirkung zweimal verursacht.

thermostat.OnTemperatureChange += cooler.OnTemperatureChanged addiert Cooler.

thermostat.OnTemperatureChange += heater.OnTemperatureChanged nimmt Cooler, wandelt es in Cooler, Heater, dann ruft set, die es mit dem alten Wert kombiniert diese verursacht Cooler, Cooler, Heater zu werden.

Ich gebe zu, ich fand dies sehr unintuitiv, aber es ist aufgrund eines banalen Bugs.

eine dritte Heizeinrichtungsleitung Hinzufügen ergibt:

Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 

in andere Heizeinrichtungsleitung Ergebnisse Hinzufügen:

Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Cooler.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 
Heater.Void OnTemperatureChanged(Single) 

Es hält immer den gleichen Präfix, das der gleiche Präfix wieder, dann Heizung.

Wenn Sie eine Empfehlung möchten: Verwenden Sie event Action<float> OnTemperatureChange; und das geht weg.

+0

Danke. Können Sie erklären, warum die Verwendung eines 'Ereignisses 'dies beseitigt? – HeyJude

+0

'operator + =' bei Ereignissen ruft den 'add'-Accessor auf. Es kombiniert selbst keine Delegierten. Ich habe in erster Linie vorgeschlagen, ein Ereignis zu verwenden, weil es Ihre Absicht besser erfasst. Der Fehler kann auf mehrere Arten entfernt werden, Ereignis ist nur eins. – usr

Verwandte Themen