10

I think the answer is NO? If there isn't, why do we have separated Delegate and MulticastDelegate classes? Maybe it's again because of "some other .NET languages"?

Cheng Chen
  • 42,509
  • 16
  • 113
  • 174

4 Answers4

14

EDIT: I thought this was part of ECMA 335, but I can't see it in there anywhere.

You can't create such a delegate type in C#, but you can in IL:

.class public auto ansi sealed Foo
       extends [mscorlib]System.Delegate
{
    // Body as normal
}

The C# compiler has no problems using such a delegate:

using System;

class Test
{
    static void Main()
    {
        Foo f = x => Console.WriteLine(x);
        f("hello");
    }
}

But the CLR does when it tries to load it:

Unhandled Exception: System.TypeLoadException: Could not load type 'Foo' from assembly 'Foo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' because it cannot inherit directly from the delegate class. at Test.Main()

Basically the Delegate/MulticastDelegate separation is an historical accident. I believe that early alpha/beta versions did make the distinction, but it proved too confusing and generally not useful - so now every delegate derives from MulticastDelegate.

(Interestingly, the C# specification only mentions MulticastDelegate once, in the list of types which can't be used as generic constraints.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • What does PEVerify say on that assembly with `Foo`? – leppie Jan 17 '11 at 08:29
  • @leppie: Haven't tried yet. Feel free to do so :) (I just ran ildasm on a "normal" declaration to get the IL, then doctored it and re-ilasmed.) – Jon Skeet Jan 17 '11 at 08:36
  • I used ilasm/ildasm to a test delegate and got the expected result in your answer. Thanks. – Cheng Chen Jan 17 '11 at 08:39
  • Is there any reason why the CLR enforces this constraint? There have been several times when I want an event to only *be able* to have one subscriber. This is possible by specifying your own `add`/`remove` but having a non-multicast delegate would make this simpler. – Jonathon Reinhart Aug 06 '12 at 22:34
  • @JonathonReinhart: No idea, I'm afraid :( – Jon Skeet Aug 06 '12 at 22:54
2

No, there isn't, because all delegates must naturally be able to be Delegate.Combineed. Delegate is there simply to wrap the non-multicasting functionality into a base class.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Even if every delegate had a single method pointer and target, Delegate.Combine could be implemented just fine: simply create an object with two fields of appropriate delegate type, which runs them sequentially. Using MulticastDelegates may offer a performance advantage in situations where delegates with a large number of sub-delegates are run frequently, but seldom involved with Combine and Remove, but I would be surprised if it yields better performance in more typical situations. Personally, I wish that there had been a mutable "event list" type, perhaps a struct with a single field... – supercat Dec 18 '11 at 19:02
  • ...of type Object, which could hold either a null, a single delegate, or an array of delegates, and which included a methods to invoke that field as appropriate as well as perform thread-safe Add and Remove operations (using Interlocked.CompareExchange); the invocation methods should offer a choice of stopping at the first exception, or letting all handlers run and throwing a BundledException with a list of all exceptions that occurred while running them. Having the event list keep delegates references, rather than a list of methods and targets would eliminate quirks in the existing approach. – supercat Dec 18 '11 at 19:11
2

System.MuticastDelegate is derived from System.Delegate. Each level within the delegate hierarchy provides a different set of services. System.Delegate is a container of the data for what method to call on a particular object. With System.MulticastDelegate comes the additional capability of not only invoking a method on a single object, but on a collections of objects. This enables multiple subscribers to an event.

Not sure, i have answered your question.

KBBWrite
  • 4,373
  • 2
  • 20
  • 22
  • 3
    While that sounds appropriate, it doesn't explain why GetInvocationList (clearly about invoking *multiple* methods) is part of Delegate, and not MulticastDelegate... – Jon Skeet Jan 17 '11 at 08:23
1

No, the CLR does not allow that.

I recall something that they wanted to expose Delegate directly, but that was never needed.

leppie
  • 115,091
  • 17
  • 196
  • 297