C#中的`event = method`是什么意思

What is meaning of `event = method` in C#

我熟悉 C# 中的事件和委托,我已经像下面这样使用了很长一段时间

// Subscribing
SomeEvent += SomeMethod;
// Unsubscribing
SomeEvent -= SomeMethod;

但是,我看到了类似下面的内容

SomeEvent = SomeMethod

这与订阅活动有何不同。在上面的代码中,SomeMethod 在引发 SomeEvent 时被调用,但它与订阅事件有何不同,它在幕后做了什么?

编辑 根据@Eldar 和@PMF 的反馈,我发现 SomeEvent = SomeMethod 被称为单播委托使用或单播使用。 为了正确理解它,我在 Unity

中快速设置了一个测试脚本
public class Testing : MonoBehaviour
{
    // UnityAction is a simple delegate
    // public delegate void UnityAction();
    private UnityAction OnTestAction;

    private void Start()
    {
        OnTestAction = OnTestActionHandler;
    }

    private void OnTestActionHandler()
    {
        Debug.Log("On Test Action Handler");
    }

    // Update is basically infinite loop in unity
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
              OnTestAction?.Invoke();
        }

        if (Input.GetKeyDown(KeyCode.A))
        {
            OnTestAction -= OnTestActionHandler;
        }
    }
}

在上面的代码中我发现它与SubscribingUnsubscribing一样工作,所以我们可以使用+=而不是=还是不好用+=什么时候只需要订阅事件到单一方法?

注意只有field-like events可以这样使用:

SomeEvent = SomeMethod;
另一方面,

SomeEvent += SomeMethod;SomeEvent -= SomeMethod; 可用于所有事件,它们分别调用 SomeEventaddremove 访问器.

这是来自语言规范的类似字段的事件:

Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be used in this way, an event [...] must not explicitly include event_accessor_declarations. Such an event can be used in any context that permits a field. The field contains a delegate which refers to the list of event handlers that have been added to the event. If no event handlers have been added, the field contains null.

通常,像事件这样的字段没有明确的 addremove 访问器。

注意他们如何使用委托类型字段存储事件处理程序列表。 SomeEvent = SomeMethod; 基本上 将字段 设置为委托,其调用列表仅包含 SomeMethod。这意味着列表中所有先前的处理程序都将被丢弃。如果您想知道如何将方法名称转换为委托,请参阅 method group conversions.

类字段事件的addremove访问器自动生成:

When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. The addition and removal operations are thread safe, and may (but are not required to) be done while holding the lock on the containing object for an instance event, or the type object for a static event.

规范并未具体说明如何实现,因此由实现决定。在 SharpLab 上,我们可以看到一种实现方式是:

private EventHandler m_SomeEvent;

private event EventHandler SomeEvent
{
    [CompilerGenerated]
    add
    {
        EventHandler eventHandler = this.SomeEvent;
        while (true)
        {
            EventHandler eventHandler2 = eventHandler;
            EventHandler value2 = (EventHandler)Delegate.Combine(eventHandler2, value);
            eventHandler = Interlocked.CompareExchange(ref this.SomeEvent, value2, eventHandler2);
            if ((object)eventHandler == eventHandler2)
            {
                break;
            }
        }
    }
    [CompilerGenerated]
    remove
    {
        EventHandler eventHandler = this.SomeEvent;
        while (true)
        {
            EventHandler eventHandler2 = eventHandler;
            EventHandler value2 = (EventHandler)Delegate.Remove(eventHandler2, value);
            eventHandler = Interlocked.CompareExchange(ref this.SomeEvent, value2, eventHandler2);
            if ((object)eventHandler == eventHandler2)
            {
                break;
            }
        }
    }
}

注意字段 m_SomeEvent,以及对 Delegate.RemoveDelegate.Combine 的调用 - 这些是将新处理程序添加到处理程序列表并从列表中删除处理程序的原因处理程序。

So can we use += instead of = or is it bad to use += when you only have to subscribe event to single method?

当你只订阅一种方法时,使用+=也不错。事实上,我 推荐 你使用 +=。你可能会说“我只想订阅一个方法”现在,但你永远不知道什么时候会改变:)