5

C# 7.3 has added support for constraining a generic type parameter to a delegate type.

public class UsingDelegate<T> where T : System.Delegate { }
public class Multicaster<T> where T : System.MulticastDelegate { }

This may be trivial, but is there any practical difference between where T : System.Delegate and where T : System.MulticastDelegate? This is undocumented on Microsoft Docs.

fghzxm
  • 1,185
  • 7
  • 19
  • I'm tempted to ask further why there are seperate `System.Delegate` and `System.MulticastDelegate` in the first place, [given](/a/31204887) [that](/a/2193248) there are no types that derive from the former but not the latter. – fghzxm Jan 24 '20 at 07:27
  • 3
    The story I've heard is that it was originally meant to be a way to optimize storage, by having single cast and multi cast in different types. In practice, only the multi cast was used so they never added other types. There is no point in having the two types right now but they're there for historical reasons. There should be no difference between your two declarations. – Lasse V. Karlsen Jan 24 '20 at 07:31
  • 1
    Regarding type parameter constraints, `where T : System.Delegate` is sufficient. Everything public in `MulticastDelegate` is an override of a virtual `Delegate` method (or defers to one, as in the case of the equality operators). Anything you need to do with `T` will get the `MulticastDelegate` implementation. Even the static `Delegate.Combine` and `Delegate.Remove` methods defer to virtual implementations which are overridden by `MulticastDelegate`. – madreflection Jan 24 '20 at 07:35

1 Answers1

3

We cannot instantiate Delegate and MulticastDelegate classes as these classes are abstract:

 public abstract class Delegate : ICloneable, ISerializable { ... }

 public abstract class MulticastDelegate : Delegate { ... }

The primary way to work with delegates is delegate keyword. The C# compiler creates instances of a class derived from MulticastDelegate when we use the C# language keyword delegate to declare delegate types.

The reason of why C# compiler creates instances of a class derived from MulticastDelegate is:

This design has its roots in the first release of C# and .NET. One goal for the design team was to ensure that the language enforced type safety when using delegates. That meant ensuring that delegates were invoked with the right type and number of arguments. And, that any return type was correctly indicated at compile time. Delegates were part of the 1.0 .NET release, which was before generics.

The best way to enforce this type safety was for the compiler to create the concrete delegate classes that represented the method signature being used.

Even though you cannot create derived classes directly, you will use the methods defined on these classes.

It can be seen that delegates were part of the 1.0 .NET release, which was before generics, so it can be concluded that constraint where T : System.Delegate { } exists in C# 7.3 by historical reason to enforce the type safety for the compiler by creating the concrete delegate classes that represented the method signature being used.

StepUp
  • 36,391
  • 15
  • 88
  • 148