68

I would like to pose this question as long as I am trying currently to dig into the use and the purpose of delegates, although it is likely to have been asked in similar formulations.

I know that delegates serve as function pointers used in C++. The matter of the fact is if in C# they serve mostly as an alternative to interfaces and polymorphism. Since I can create subclasses of a specific class and supply them the appropriate methods to each one, what offer delegates additionally to that? Are there cases that stipulate their use or is merely the maintainability of the code improved when delegates used? Would you recommend their wide deployment over interfaces?

I am speaking solely about delegates and I want to distinguish their role from the events role.

arjacsoh
  • 8,932
  • 28
  • 106
  • 166
  • 5
    "The matter of the fact is if in C# they serve mostly an alternative to interfaces and polymorphism" - please explain your reasoning. – Oded Jan 01 '12 at 19:19
  • 7
    It is only (an indirect) question. I perceive their functionality as described in my question and I want to know if you agree and if this is true. – arjacsoh Jan 01 '12 at 19:42

6 Answers6

85

Yes, delegates are in many ways like single-method interfaces. However:

  • There is support built into the CLR for them
  • There's support in the framework for them, including multi-cast abilities and asynchronous invocation
  • There's additional C#/VB language support in the form of method group conversions, lambda expressions, anonymous methods
  • They're mandated for events (i.e. events and delegates are a sort of matching pair)
  • They mean you don't need to implement an interface in a separate class for each delegate instance you want to create.

The last point is the most important one - consider a LINQ expression of:

var query = collection.Where(x => x > 5)
                      .Select(x => x * x);

Now imagine if to express the logic of x > 5 and x * x you had to write a separate class for each expression, and implement an interface: the amount of cruft vs useful code would be ridiculous. Now of course the language could have been designed to allow conversions from lambda expressions into interface implementations via separate classes, but then you'd still lose the benefit of being able to simply write a separate method and create a delegate with that as the target. You'd also still lose the multi-cast abilities.

As a similar thought exercsise, consider looping statements such as while and for. Do we really need them when we've got goto? Nope. But life is much better with them. The same is true of delegates - and indeed properties, events, etc. They all make the development simpler.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    I wouldn't regard the Linq example as showing an advantage of delegates; even if delegate type `Func` were replaced with interface `IFunc`, a compiler could easily define a class which implements that interface, and includes a public static property that returns a private static instance. Such an approach would work out about the same as delegates for lambda expressions that don't close over any locals, and would be more efficient than delegates for lambda expressions that do close over locals. – supercat Jan 03 '12 at 18:37
  • @supercat: The LINQ example shows how having syntactic sugar for this is greatly beneficial. It *could* be done with interfaces, sure - but it isn't in C#, and isn't *yet* in Java. Note that for a lambda expression which closes over local variables, you couldn't have a single instance anyway, as you'd need to create a new instance each time to hold the captured variable. – Jon Skeet Jan 03 '12 at 18:55
  • 4
    I guess I'd misread the original question as more theoretical than practical; if the .net framework had been designed around interfaces rather than delegates, compilers would almost certainly provide the same types of support for the former as they do for the latter. As for closures, presently creating a closure requires the creation of both an object to hold the variables and a delegate which holds a reference to that object and the desired function; if one could use interfaces instead of delegates, the compiler could simply create one object that would serve both functions. – supercat Jan 03 '12 at 18:59
  • 1
    @supercat: That's true, although I wonder whether that's optimized somehow internally. I mentioned the possibility of converting lambda expressions to interfaces in my answer - but there are the other benefits around asynchrony and multi-cast nature as well, and the fact that they're *guaranteed* to be a single method, rather than just an interface which could expand (and then wouldn't be suitable for event handling, for example, as there'd be no single method to call). – Jon Skeet Jan 03 '12 at 19:05
  • @JonSkeet: Adding members to an interface has always been regarded as a breaking change. If the framework defines `IAction` as having a single member `Invoke(T p1, T p2)`, that's all that interface will ever have. It's entirely possible that a class may have many implement `IAction` for many different combinations of T and U; if one only had an instance of such a class, cast to `Object`, one wouldn't know which interface to call, but so what? It isn't generally possible, except via Reflection, to call a delegate whose signature isn't known at compile time. – supercat Jan 03 '12 at 19:18
  • @supercat: Yes, it's always a breaking change from the *implementing* side, but this would also be from the *calling* side. And don't forget that with delegates, it's not just the framework that's declaring the type... All of this could be handled in some form or other - but by effectively making the convention part of the framework/language/CLR, it's tidier... much like properties, foreach loops, etc. – Jon Skeet Jan 03 '12 at 19:22
  • @JonSkeet: If every delegate type which took only value parameters were defined as implementing an interface `IAction`, I would expect a lot of code could accept the interface types rather than requiring delegates; that would seem the best of both worlds. Things like event-subscription-management routines would require explicit support for each possible number of parameters, but if one accepted the normal event pattern that wouldn't be a problem. – supercat Jan 03 '12 at 19:29
  • @supercat: If generics had come along before .NET 1, maybe that would have been the approach taken. It wouldn't support ref/out parameters that way, and you'd need `IFunc` as well, but it could work... – Jon Skeet Jan 03 '12 at 20:25
  • @JonSkeet: BTW, I just realized an approach that could perhaps be added to .net 5.0 without breaking much of anything: have each delegate type (e.g. `Action`) define and implement an interface type (e.g. `Action.IInvoke`). Most things that now accept an `Action` could instead accept an `Action.IInvoke`, but other classes could implement `Action.IInvoke` as well. This approach can only support covariance if delegates can, but the solution for that is to allow delegates to have covariant type parameters. – supercat Jan 03 '12 at 21:07
  • @supercat: Delegates can already support generic variance, so that's okay. It could be done, but I'm not sure it meet the benefit/cost requirement. – Jon Skeet Jan 03 '12 at 21:33
  • @JonSkeet: Delegates don't really support variance; I think Eric Lippert blogged about that. If one has two delegate variables of type `Action`, and two of type `Action – supercat Jan 04 '12 at 21:46
  • @supercat: Generic variance *is* supported for delegates as of C# 4, which is why it's `Action` in .NET 4, etc. Previously there was a different sort of pseudo-variance available. Assignments via method group conversions would do something different, sure - but if you create a delegate instance first, you could assign the same reference to both variables, and the values would be equal. – Jon Skeet Jan 04 '12 at 21:48
  • @JonSkeet: I can't get that to work, and I'm not sure how it could given the way MultiCastDelegate is implemented. From what I understand, a MulticastDelegate has no way of storing the actual types of any delegates that were combined to produce it, so if an `Action – supercat Jan 05 '12 at 16:49
  • 1
    @supercat: Combining delegates does indeed form a problem when used with variance - but single-action delegates work fine. For example: ` Action x = o => Console.WriteLine(o); Action y = x; Console.WriteLine(x == y);` - that will print True. (It requires C# 4 and .NET 4 though.) – Jon Skeet Jan 05 '12 at 17:19
  • @JonSkeet: In what scenarios would you recommend using interfaces instead of delegates? – Jon Nov 08 '13 at 01:22
  • eg, would you agree with the advice given in http://msdn.microsoft.com/en-us/library/ms173173%28v=vs.100%29.aspx ? – Jon Nov 08 '13 at 01:32
  • @Jon: They're good rules of thumb, but I suspect there are situations where they'd be worth bending. I can't immediately think of any *better* rules of thumb. – Jon Skeet Nov 08 '13 at 06:46
36

The biggest practical difference is that you can provide different delegate instances for the same delegate from the same class, while you cannot do it with interfaces.

delegate void XYZ(int p);

interface IXyz {
    void doit(int p);
}

class One {
    // All four methods below can be used to implement the XYZ delegate
    void XYZ1(int p) {...}
    void XYZ2(int p) {...}
    void XYZ3(int p) {...}
    void XYZ4(int p) {...}
}

class Two : IXyz {
    public void doit(int p) {
        // Only this method could be used to call an implementation through an interface
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
21

From When to Use Delegates Instead of Interfaces (MSDN):

Both delegates and interfaces enable a class designer to separate type declarations and implementation. A given interface can be inherited and implemented by any class or struct. A delegate can be created for a method on any class, as long as the method fits the method signature for the delegate. An interface reference or a delegate can be used by an object that has no knowledge of the class that implements the interface or delegate method. Given these similarities, when should a class designer use a delegate and when should it use an interface?

Use a delegate in the following circumstances:

  • An eventing design pattern is used.
  • It is desirable to encapsulate a static method.
  • The caller has no need to access other properties, methods, or interfaces on the object implementing the method.
  • Easy composition is desired.
  • A class may need more than one implementation of the method.

Use an interface in the following circumstances:

  • There is a group of related methods that may be called.
  • A class only needs one implementation of the method.
  • The class using the interface will want to cast that interface to other interface or class types.
  • The method being implemented is linked to the type or identity of the class: for example, comparison methods.

One good example of using a single-method interface instead of a delegate is IComparable or the generic version, IComparable(Of T). IComparable declares the CompareTo method, which returns an integer that specifies a less than, equal to, or greater than relationship between two objects of the same type. IComparable can be used as the basis of a sort algorithm. Although using a delegate comparison method as the basis of a sort algorithm would be valid, it is not ideal. Because the ability to compare belongs to the class and the comparison algorithm does not change at run time, a single-method interface is ideal.

From Delegates Vs Interfaces in C#:

Delegates and Interfaces are two distinct concepts in C# but they share a commonality. Both delegates and interfaces only include the declaration. Implementation is done by a different programming object.

Sam
  • 40,644
  • 36
  • 176
  • 219
Lion
  • 18,729
  • 22
  • 80
  • 110
  • 2
    Helpful answer; if you or anyone else could add examples of your 2nd-5th bullet points of where a delegate can be useful, that would be great too. Eventing pattern I don't think needs any examples since it's so widely discussed. – Levin Magruder Jan 01 '12 at 19:31
4

Delegates and Interfaces are two distinct concepts in C#.

Interfaces allow to extend some object's functionality, it's a contract between the interface and the object that implements it, while delegates are just safe callbacks, they are a sort of function pointers.

aleroot
  • 71,077
  • 30
  • 176
  • 213
2

The only real advantages of delegates over interfaces are

  1. Delegates could deal with different argument types even before .Net supported generics.
  2. A class can create delegates exposing multiple different methods sharing the same signature; replacing delegates with interfaces would mean that every class could expose one method that implemented each delegate-style interface without creating helper classes, but would need a helper class for each additional implementation.

When .net did not support generics, delegates were essential part of it since declaring distinct non-generic interfaces for each and every different function signature one would want to pass would have been unworkable. If .net had supported generics from the beginning, delegates would not have been necessary except for certain scenarios involving Reflection, and even there it would perhaps have been most useful to have the type Action<T,U> be an implementation of IAction<T,U> (so that code which simply needs something it can Invoke would use the interface). An interface-based approach would have required the creation of single-method classes in cases where classes need to create delegates exposing multiple methods, but would have eliminated the need to create separate delegate instances in the many common cases where the number of methods of a given signature to be exposed is precisely one.

Incidentally, replacing delegates with interfaces would in no way prevent the creation of a general-purpose Combine method. Indeed, interface covariance could make such a method work better than the existing Delegate.Combine in many respects. Implementing a method analogous to Delegate.Remove would be at best clunky and annoying, but I can think of no situation other than event subscription management which would require the use of Delegate.Remove, and event subscription could best be handled using other approaches anyway.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

Answering it quite late. Wanted to highlight another cool thing that can be achieved via delegates, am not sure whether this feature was available earlier.

A delegate can point to multiple functions and just a single invocation would invoke all the functions.

public delegate void Log(string data);

private void LogInFile(string data)
{
    Console.WriteLine("Logging in file. Data:" + data);
}

private void LogInConsole(string data)
{
    Console.WriteLine("Logging in console. Data:" + data);
}

private void LogInMemory(string data)
{
    Console.WriteLine("Logging in memory. Data:" + data);
}

[Test]
public void TestDelegate()
{
    Log delegateLogger = LogInFile;
    delegateLogger += LogInConsole;
    delegateLogger += LogInMemory;

    delegateLogger("test");

}


Standard Output: 
Logging in file. Data:test
Logging in console. Data:test
Logging in memory. Data:test
Arun
  • 19
  • 2