简体   繁体   中英

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

I am familiar with events and delegates in C#, and I have been using them like following for quite some time

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

But, I have seen something like following

SomeEvent = SomeMethod

How it is different from subscribing to an event. In above code SomeMethod gets called when SomeEvent is raised, but how it is different from subscribing to an event, what it does behind the scene?

Edit Based on feedback from @Eldar and @PMF I found out that SomeEvent = SomeMethod is called single cast delegate usage or Unicast usage. To understand it properly I quickly setup a test script in 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;
        }
    }
}

In above code I found out that it works same as Subscribing and Unsubscribing , So can we use += instead of = or is it bad to use += when you only have to subscribe event to single method?

Note that only field-like events can be used in this way:

SomeEvent = SomeMethod;

SomeEvent += SomeMethod; and SomeEvent -= SomeMethod; on the other hand can be used with all events, and they call the add and remove accessors of SomeEvent respectively.

Here's what a field-like event is, from the language spec:

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.

In general, a field like event does not have explicit add and remove accessors.

Notice how they have a delegate-typed field storing the list of event handlers. SomeEvent = SomeMethod; basically sets the field to a delegate whose invocation list contains only SomeMethod . This means that all the previous handlers in the list are discarded. If you are wondering how a method name can be converted to a delegate, see method group conversions .

The add and remove accessors of field-like events are automatically generated:

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.

The spec doesn't say exactly how, so that's up to the implementation to decide. On SharpLab , we can see that one implementation would be:

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

Note the field m_SomeEvent , and the calls to Delegate.Remove and Delegate.Combine - those are what adds the new handler to the list of handlers, and removes a handler from the list of handlers.

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

It's not bad to use += when you subscribe to only one method. In fact, I would recommend you to use += . You may say "I only want to subscribe to a single method" now , but you never know when that's going to change:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM