Recently I came across a Microsoft interface with a quite unusual API:
public interface IHostApplicationLifetime
{
public CancellationToken ApplicationStarted { get; }
public CancellationToken ApplicationStopping { get; }
public CancellationToken ApplicationStopped { get; }
}
The documentation of the property ApplicationStopping suggests confusingly that this property is actually an event (emphasis added):
Triggered when the application host is performing a graceful shutdown. Shutdown will block until this event completes.
It seems that what should be a traditional EventHandler event, has been replaced with a CancellationToken property. This is how I expected this
interface to be:
public interface IHostApplicationLifetime
{
public event EventHandler ApplicationStarted;
public event EventHandler ApplicationStopping;
public event EventHandler ApplicationStopped;
}
My question is, are these two notifications mechanisms equivalent? If not, what are the pros and cons of each approach, from the perspective of an API designer? In which circumstances a CancellationToken property is superior to a classic event?
Microsoft should have been more careful with the documentation. It is confusing to describe the CancellationTokens as events to be "triggered".
I'm certainly not a C# language expert so hopefully the community will let us know if I'm missing import points. But let me take a stab a few things...
So your question: are they equivalent.. only in the sense that they both provide a way to register and invoke callbacks. But for a lot of other reasons, no.
CancellationTokens are wrapper around CancellationTokenSource. They tie into the Task implementation. They are thread safe. They can be invoked externally and can be invoked by a timer. You can chain multiple CancellationTokenSource together. They maintain state which indicates if they are, or are not, canceled and you can query that state.
C# events, the language feature, are in the words of the documentation a special multicast delegate. They can only be invoked within the class where they are declared. They are not really thread safe. They are baked into XAML and WPF.
I'm not going to comment too much on where one is superior to the other as they are very different. In the normal course I don't think you'd consider events in situations where you would consider CancellationTokens. They overlapped in the case of IHostApplicationLifetime mainly because of bad documentation and the redesign of the hosting infrastructure for .NET Core. As @EricLippert mentioned this link provides a great overview of that.