如何构建委托调用列表

本文关键字:调用 列表 构建 何构建 | 更新日期: 2023-09-27 18:05:44

我试图理解组合委托是如何工作的。在下面的代码中,我将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更改回其通常的实现,我们将看到CoolerHeater的单个OnTemperatureChanged

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

如何构建委托调用列表

+=为委托调用Delegate.Combinethermostat.OnTemperatureChange += cooler.OnTemperatureChanged;调用这个函数两次:一次在Main中,一次在set_OnTemperatureChange中。所以这是一个普通的bug,会导致两次副作用。

thermostat.OnTemperatureChange += cooler.OnTemperatureChanged添加Cooler

thermostat.OnTemperatureChange += heater.OnTemperatureChangedCooler,将其转换为Cooler, Heater,然后调用set,将其与旧值合并,使其成为Cooler, Cooler, Heater

我承认我发现这很不直观,但这是由于一个普通的错误。

添加第三条加热器线导致:

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;,这就消失了。