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 6333361
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 24, 20262026-05-24T18:26:45+00:00 2026-05-24T18:26:45+00:00

I have the following piece of code in a base-class: public static void InvokeExternal(Delegate

  • 0

I have the following piece of code in a base-class:

public static void InvokeExternal(Delegate d, object param, object sender)
{
    if (d != null)
    {
        //Check each invocation target
        foreach (Delegate dDelgate in d.GetInvocationList())
        {
            if (dDelgate.Target != null && dDelgate.Target is System.ComponentModel.ISynchronizeInvoke
                && ((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).InvokeRequired)
            {
                //If target is ISynchronizeInvoke and Invoke is required, invoke via ISynchronizeInvoke
                ((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).Invoke(dDelgate, new object[] { sender, param });
            }
            else
            {
                //Else invoke dynamically
                dDelgate.DynamicInvoke(sender, param);
            }
        }
    }
}

This code sample is responsible for invoking an event, represented as multicast delegate, where the invocation targets include small classes which do not care about cross-threading, but also classes which implement ISynchronizeInvoke and care a lot about cross-threading, like Windows Forms Controls.

In theory, this snippet works pretty fine, no errors occur. But the DynamicInvoke is incredibly slow, not to say it’s the current bottleneck of the application.

So, there goes my question: Is there any way to speed up this little function without breaking the functionally to subscribe to the event directly?

The signature of all events/delegates is (object sender, EventArgs param)

  • 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-05-24T18:26:47+00:00Added an answer on May 24, 2026 at 6:26 pm

    If dDelegate is a known type (ie Action) you could always cast to it and call it directly.

    With that said if you are on .NET3.5 you can use Expression trees to get a fair bit of optimization. My example uses the concurrent dictionary in .NET4 but that’s replacable with a normal dictionary and a lock.

    The idea is as following: The delegate holds which method it’s calling to. For each unique method that is called I create (using Expression trees) a compiled delegate that calls that specific method. Creating a compiled delegate is expensive that’s why it’s important to cache it but once created the compiled delegate is as fast as a normal delegate.

    On my machine 3,000,000 calls took 1 sec with the compiled delegate and 16 sec with DynamicInvoke.

    // Comment this line to use DynamicInvoke instead as a comparison
    #define USE_FAST_INVOKE
    
    
    namespace DynInvoke
    {
        using System;
        using System.Collections.Concurrent;
        using System.Linq.Expressions;
        using System.Reflection;
    
        static class Program
        {
            delegate void CachedMethodDelegate (object instance, object sender, EventArgs param);
    
            readonly static ConcurrentDictionary<MethodInfo, CachedMethodDelegate> s_cachedMethods =
                new ConcurrentDictionary<MethodInfo, CachedMethodDelegate> ();
    
            public static void InvokeExternal(Delegate d, object sender, EventArgs param)
            {
                if (d != null)
                {
                    //Check each invocation target            
                    foreach (var dDelgate in d.GetInvocationList())
                    {
                        if (
                                dDelgate.Target != null
                            &&  dDelgate.Target is System.ComponentModel.ISynchronizeInvoke
                            &&  ((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).InvokeRequired
                            )
                        {
                            //If target is ISynchronizeInvoke and Invoke is required, invoke via ISynchronizeInvoke                    
                            ((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).Invoke(dDelgate, new object[] { sender, param });
                        }
                        else
                        {
    #if USE_FAST_INVOKE
                            var methodInfo = dDelgate.Method;
    
                            var del = s_cachedMethods.GetOrAdd (methodInfo, CreateDelegate);
    
                            del (dDelgate.Target, sender, param);
    #else
                            dDelgate.DynamicInvoke (sender, param);
    #endif
                        }
                    }
                }
            }
    
            static CachedMethodDelegate CreateDelegate (MethodInfo methodInfo)
            {
                var instance = Expression.Parameter (typeof (object), "instance");
                var sender = Expression.Parameter (typeof (object), "sender");
                var parameter = Expression.Parameter (typeof (EventArgs), "parameter");
    
                var lambda = Expression.Lambda<CachedMethodDelegate>(
                    Expression.Call (
                        Expression.Convert (instance, methodInfo.DeclaringType),
                        methodInfo,
                        sender,
                        parameter
                        ),
                    instance,
                    sender,
                    parameter
                    );
    
                return lambda.Compile ();
            }
    
            class MyEventListener
            {
                public int Count;
    
                public void Receive (object sender, EventArgs param)
                {
                    ++Count;
                }
            }
    
            class MyEventSource
            {
                public event Action<object, EventArgs> AnEvent;
    
                public void InvokeAnEvent (EventArgs arg2)
                {
                    InvokeExternal (AnEvent, this, arg2);
                }
            }
    
            static void Main(string[] args)
            {
    
                var eventListener = new MyEventListener ();
                var eventSource = new MyEventSource ();
    
                eventSource.AnEvent += eventListener.Receive;
    
                var eventArgs = new EventArgs ();
                eventSource.InvokeAnEvent (eventArgs);
    
                const int Count = 3000000;
    
                var then = DateTime.Now;
    
                for (var iter = 0; iter < Count; ++iter)
                {
                    eventSource.InvokeAnEvent (eventArgs);
                }
    
                var diff = DateTime.Now - then;
    
                Console.WriteLine (
                    "{0} calls took {1:0.00} seconds (listener received {2} calls)", 
                    Count, 
                    diff.TotalSeconds,
                    eventListener.Count
                    );
    
                Console.ReadKey ();
            }
        }
    }
    

    Edit: As OP uses .NET2 I added an example that should be compatible with .NET2 runtime (as I use VS2010 I might use some new language features by mistake but I did compile using .NET2 runtime).

    // Comment this line to use DynamicInvoke instead as a comparison
    #define USE_FASTER_INVOKE
    
    namespace DynInvoke
    {
        using System;
        using System.Globalization;
        using System.Reflection.Emit;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Reflection;
    
        static class FasterInvoke
        {
            delegate void CachedMethodDelegate (object instance, object sender, EventArgs param);
    
            readonly static Dictionary<MethodInfo, CachedMethodDelegate> s_cachedMethods =
                new Dictionary<MethodInfo, CachedMethodDelegate> ();
    
            public static void InvokeExternal (Delegate d, object sender, EventArgs param)
            {
                if (d != null)
                {
                    Delegate[] invocationList = d.GetInvocationList ();
                    foreach (Delegate subDelegate in invocationList)
                    {
                        object target = subDelegate.Target;
                        if (
                            target != null
                            && target is ISynchronizeInvoke
                            && ((ISynchronizeInvoke)target).InvokeRequired
                            )
                        {
                            ((ISynchronizeInvoke)target).Invoke (subDelegate, new[] { sender, param });
                        }
                        else
                        {
    #if USE_FASTER_INVOKE
                            MethodInfo methodInfo = subDelegate.Method;
    
                            CachedMethodDelegate cachedMethodDelegate;
                            bool result;
    
                            lock (s_cachedMethods)
                            {
                                result = s_cachedMethods.TryGetValue (methodInfo, out cachedMethodDelegate);
                            }
    
                            if (!result)
                            {
                                cachedMethodDelegate = CreateDelegate (methodInfo);
                                lock (s_cachedMethods)
                                {
                                    s_cachedMethods[methodInfo] = cachedMethodDelegate;
                                }
                            }
    
                            cachedMethodDelegate (target, sender, param);
    #else
                            subDelegate.DynamicInvoke (sender, param);
    #endif
                        }
                    }
                }
            }
    
            static CachedMethodDelegate CreateDelegate (MethodInfo methodInfo)
            {
                if (!methodInfo.DeclaringType.IsClass)
                {
                    throw CreateArgumentExceptionForMethodInfo (
                        methodInfo, 
                        "Declaring type must be class for method: {0}.{1}"
                        );
                }
    
    
                if (methodInfo.ReturnType != typeof (void))
                {
                    throw CreateArgumentExceptionForMethodInfo (
                        methodInfo,
                        "Method must return void: {0}.{1}"
                        );
                }
    
                ParameterInfo[] parameters = methodInfo.GetParameters ();
                if (parameters.Length != 2)
                {
                    throw CreateArgumentExceptionForMethodInfo (
                        methodInfo,
                        "Method must have exactly two parameters: {0}.{1}"
                        );
                }
    
    
                if (parameters[0].ParameterType != typeof (object))
                {
                    throw CreateArgumentExceptionForMethodInfo (
                        methodInfo,
                        "Method first parameter must be of type object: {0}.{1}"
                        );
                }
    
                Type secondParameterType = parameters[1].ParameterType;
                if (!typeof (EventArgs).IsAssignableFrom (secondParameterType))
                {
                    throw CreateArgumentExceptionForMethodInfo (
                        methodInfo,
                        "Method second parameter must assignable to a variable of type EventArgs: {0}.{1}"
                        );
                }
    
                // Below is equivalent to a method like this (if this was expressible in C#):
                //  void Invoke (object instance, object sender, EventArgs args)
                //  {
                //      ((<%=methodInfo.DeclaringType%>)instance).<%=methodInfo.Name%> (
                //          sender,
                //          (<%=secondParameterType%>)args
                //          );
                //  }
    
                DynamicMethod dynamicMethod = new DynamicMethod (
                    String.Format (
                        CultureInfo.InvariantCulture,
                        "Run_{0}_{1}",
                        methodInfo.DeclaringType.Name,
                        methodInfo.Name
                        ),
                    null,
                    new[]
                        {
                            typeof (object),
                            typeof (object),
                            typeof (EventArgs)
                        },
                    true
                    );
    
                ILGenerator ilGenerator = dynamicMethod.GetILGenerator ();
                ilGenerator.Emit (OpCodes.Ldarg_0);
                ilGenerator.Emit (OpCodes.Castclass, methodInfo.DeclaringType);
                ilGenerator.Emit (OpCodes.Ldarg_1);
                ilGenerator.Emit (OpCodes.Ldarg_2);
                ilGenerator.Emit (OpCodes.Isinst, secondParameterType);
                if (methodInfo.IsVirtual)
                {
                    ilGenerator.EmitCall (OpCodes.Callvirt, methodInfo, null);                
                }
                else
                {
                    ilGenerator.EmitCall (OpCodes.Call, methodInfo, null);                
                }
                ilGenerator.Emit (OpCodes.Ret);
    
                return (CachedMethodDelegate)dynamicMethod.CreateDelegate (typeof (CachedMethodDelegate));
            }
    
            static Exception CreateArgumentExceptionForMethodInfo (
                MethodInfo methodInfo, 
                string message
                )
            {
                return new ArgumentException (
                    String.Format (
                        CultureInfo.InvariantCulture,
                        message,
                        methodInfo.DeclaringType.FullName,
                        methodInfo.Name
                        ),
                    "methodInfo"
                    );
            }
        }
    
        static class Program
        {
            class MyEventArgs : EventArgs
            {
    
            }
    
            class MyEventListener
            {
                public int Count;
    
                public void Receive (object sender, MyEventArgs param)
                {
                    ++Count;
                }
            }
    
            delegate void MyEventHandler (object sender, MyEventArgs args);
    
            class MyEventSource
            {
                public event MyEventHandler AnEvent;
    
                public void InvokeAnEvent (MyEventArgs arg2)
                {
                    FasterInvoke.InvokeExternal (AnEvent, this, arg2);
                }
            }
    
            static void Main (string[] args)
            {
                MyEventListener eventListener = new MyEventListener ();
                MyEventSource eventSource = new MyEventSource ();
    
                eventSource.AnEvent += eventListener.Receive;
    
                MyEventArgs eventArgs = new MyEventArgs ();
                eventSource.InvokeAnEvent (eventArgs);
    
                const int count = 5000000;
    
                DateTime then = DateTime.Now;
    
                for (int iter = 0; iter < count; ++iter)
                {
                    eventSource.InvokeAnEvent (eventArgs);
                }
    
                TimeSpan diff = DateTime.Now - then;
    
                Console.WriteLine (
                    "{0} calls took {1:0.00} seconds (listener received {2} calls)",
                    count,
                    diff.TotalSeconds,
                    eventListener.Count
                    );
    
                Console.ReadKey ();
            }
        }
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have the following piece of code in my DataModel.cs class: public User ValidateUser(string
I have following piece of code: public void ProcessRequest (HttpContext context) { context.Response.ContentType =
I have following piece of code: class Test{ private: int id; public: Test(int v):id(v)
I have the following piece of code pattern: void M1(string s, string v) {
I have the following piece of code in Visual C++ 2005 : : class
I have the following piece of code and when I use Instruments/Object Allocations, it
I have following piece of code: customObject* object; std::list<customObject> objects; for(int i = 0;
I have the following piece of code: void TestFunc(const void * const Var1, const
I have following piece of code: typedef uint8_t array_t[8]; static array_t _my_array; static const
The following piece of C# code does not compile: public class A { public

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.