Delegates allow to pass in a method as parameter to another method.

To some extent creating an interface with a callback method can provide partial implementation of this functionality, but this doesn't allow to specify multiple different methods as code to be executed on callback.

See https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates

In addition, anonymous methods and lambda expressions provide an extension to this principle:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/anonymous-methods

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions