Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8223045
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 7, 20262026-06-07T14:32:03+00:00 2026-06-07T14:32:03+00:00

When delegate keyword is used in C#, the C# compiler automatically generates a class

  • 0

When delegate keyword is used in C#, the C# compiler automatically generates a class derived from System.MulticastDelegate class.

This compiler generated class contains 3 methods as well: Invoke, BeginInvoke and EndInvoke.

All these three methods are marked public virtual extern but interestingly the class itself is marked sealed.

Virtual methods defined in a sealed class not only strikes as counter-intuitive but are actually illegal in C#.

So my question is, is there a specific reason for this or is it just one of those harmless things done keeping in mind some hypothetical future enhancement?

Edit 1:

Can the reason be to force use of ‘callVirt’ IL opcode as opposed to ‘call’ so that delegate object is always checked for null by the CLR before trying to execute any of the three methods? Though I fail to see why a delegate should be a special case in this respect.

Also isn’t it a performance hit to force use of callvirt (though it may be minuscule)

Edit 2:

Added CIL tag, as it turns out that the C# way of defining delegates is in fact mandated by the CIL standard. Standard states that (following is not full text)

Delegates shall have a base type of System.Delegate. Delegates shall
be declared sealed, and the only members a delegate shall have are
either the first two or all four methods as specified here. These
methods shall be declared runtime and managed. They shall not have a
body, since that body shall be created automatically by the VES. Other
methods available on delegates are inherited from the class
System.Delegate in the Base Class Library. The delegate methods are:

  1. The instance constructor
  2. The Invoke method shall be virtual
  3. The BeginInvoke method, if present, shall be virtual
  4. The EndInvoke method shall be virtual

So this is definitely not a side effect of compiler process or is similar to other interesting compiler outputs.

If standard emphasizes something, it must be for some good reason and rationale.

So the question now is why does CIL standard for delegates emphasizes on sealed and virtual at the same time?

Does the catch lie here?:

They shall not have a body, since that body shall be created automatically by the VES.

Are they marked virtual so that the VES/CLR generated body can be executed on invocation of these methods?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-07T14:32:06+00:00Added an answer on June 7, 2026 at 2:32 pm

    As I noted in my question that this sealed virtual anomaly is in fact mandated by CIL standard. It remains unclear why CIL standard specifically mentions that delegate methods Invoke, BeginInvoke and EndInvoke should be virtual while at the same time mandating to seal the Delegate inherited class.

    Also, after going through SSCLI code I learnt that internal optimization of JIT compiler automatically translates any callvirt call on a virtual method of a sealed class to normal call with additional null check. This means that delegates do not suffer any performance hit when its Invoke (or any of the other two) method is called through callvirt instruction despite being marked virtual in the IL.

    When a delegate’s invoke is called, CLR automatically emits a highly optimized body for this method as opposed to compiling IL code to generate body which it does for ‘normal’ methods. This has nothing to do with being marked virtual in the IL.

    I have also verified by hand modifying IL code and re-assembling it that virtual can be safely removed from the generated delegate class’s IL code. The generated assembly despite being in violation of the CIL standard runs perfectly fine.

    .class private auto ansi beforefieldinit MainApp
           extends [mscorlib]System.Object
    {
      .class auto ansi sealed nested private Echo
             extends [mscorlib]System.MulticastDelegate
      {
        .method public hidebysig specialname rtspecialname 
                instance void  .ctor(object 'object',
                                     native int 'method') runtime managed
        {
        } // end of method Echo::.ctor
    
        .method public hidebysig instance int32  Invoke(int32 i) runtime managed
        {
        } // end of method Echo::Invoke
    
        .method public hidebysig instance class [mscorlib]System.IAsyncResult 
                BeginInvoke(int32 i,
                            class [mscorlib]System.AsyncCallback callback,
                            object 'object') runtime managed
        {
        } // end of method Echo::BeginInvoke
    
        .method public hidebysig instance int32  EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
        {
        } // end of method Echo::EndInvoke
    
      } // end of class Echo
    
      .method public hidebysig static void  Main() cil managed
      {
        .entrypoint
        // Code size       34 (0x22)
        .maxstack  3
        .locals init ([0] class MainApp app,
                 [1] class MainApp/Echo dele)
        IL_0000:  nop
        IL_0001:  newobj     instance void MainApp::.ctor()
        IL_0006:  stloc.0
        IL_0007:  ldloc.0
        IL_0008:  ldftn      instance int32 MainApp::DoEcho(int32)
        IL_000e:  newobj     instance void MainApp/Echo::.ctor(object,
                                                               native int)
        IL_0013:  stloc.1
        IL_0014:  ldloc.1
        IL_0015:  ldc.i4.5
        //callvirt can also be replaced by call without affecting functionality
        // since delegate object is essentially not null here
        IL_0016:  callvirt   instance int32 MainApp/Echo::Invoke(int32)
        IL_001b:  call       void [mscorlib]System.Console::WriteLine(int32)
        IL_0020:  nop
        IL_0021:  ret
      } // end of method MainApp::Main
    
      .method private hidebysig instance int32 
              DoEcho(int32 i) cil managed
      {
        // Code size       7 (0x7)
        .maxstack  1
        .locals init ([0] int32 CS$1$0000)
        IL_0000:  nop
        IL_0001:  ldarg.1
        IL_0002:  stloc.0
        IL_0003:  br.s       IL_0005
    
        IL_0005:  ldloc.0
        IL_0006:  ret
      } // end of method MainApp::DoEcho
    
      .method public hidebysig specialname rtspecialname 
              instance void  .ctor() cil managed
      {
        // Code size       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.0
        IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
        IL_0006:  ret
      } // end of method MainApp::.ctor
    
    } // end of class MainApp
    

    Note that I have converted the virtual methods to normal instance methods.

    Since this changed IL runs perfectly fine it proves that standard mandated virtual methods in the sealed delegate class are not necessary. They can be normal instance methods as well.

    So in all probability this anomaly is either to emphasize that calling these three delegate methods will in-fact result in calling of some other method (i.e. run-time polymorphism just like ‘normal’ virtual methods) or this has been so to accommodate some future hypothetical enhancement related to delegates.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a C# code like this: using System; delegate int anto(int x); class
Compiler Error Keyword 'this' is not available in the current context delegate void CallBack(int
Like Anonymous Methods ,the delegates i am declaring down using delegate keyword are anonymous
using System; public delegate void Printer(string s); class Program { public static void Main(string[]
In Delphi we can delegate the implementation of an interface to another class, I'm
From MSDN doc : A delegate is a type that safely encapsulates a method,
I'm writing a delegate class but it fails to take const member functions. Here
this.Invoke((MethodInvoker)delegate { code; }); This results in exception as Cannot access a disposed object.
On my app delegate class I have a simple property @property (strong, nonatomic) LoginAppDelegate
this works: //delegate Parallel.For(1023456789, 1033456789, delegate(long i) { if (i % 10000000 == 0)

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.