如何构建委托调用列表?

时间:2016-09-03 23:45:34

标签: c# delegates

我正在努力了解如何组合代表的工作方式。在下面的代码中,我将set的常规实现(通过简单赋值,使用=运算符)更改为格式不正确(使用+=运算符)。

以下代码:

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();
    }
}

打印:

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

当然,如果我将set更改回其通常的实施方式,我们会看到OnTemperatureChangedCooler的{​​{1}} {。}}。

我想了解为什么以这种方式设置委托会导致这种形式的调用列表?

1 个答案:

答案 0 :(得分:1)

+=代表致电Delegate.Combinethermostat.OnTemperatureChange += cooler.OnTemperatureChanged;将此调用两次:一次进入Main,一次进入set_OnTemperatureChange。所以这是一个平庸的错误导致副作用两次。

thermostat.OnTemperatureChange += cooler.OnTemperatureChanged添加Cooler

thermostat.OnTemperatureChange += heater.OnTemperatureChanged需要Cooler,将其转换为Cooler, Heater,然后调用set,将其与旧值相结合,使其成为Cooler, Cooler, Heater

我承认我发现这非常不直观,但这是由于一个平庸的错误。

添加第3个加热线会导致:

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)
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)

它始终保持相同的前缀,再次使用相同的前缀,然后加热器。

如果您需要推荐:使用event Action<float> OnTemperatureChange;,这就会消失。