1

I have seen the following questions Generating Delegate Types dynamically in C# and How to create a dynamic delegate object by type in C#? and I'm afraid I dont fully understand the concepts still.

The problem I am attempting to resolve is this: A third party library provides the following functions

AppendIncomingPacketHandler<incomingObjectType>(
    string packetTypeStr,
    NetworkComms.PacketHandlerCallBackDelegate<incomingObjectType> packetHandlerDelgatePointer)

and

AppendIncomingPacketHandler<incomingObjectType>(
    string packetTypeStr,
    NetworkComms.PacketHandlerCallBackDelegate<incomingObjectType> packetHandlerDelgatePointer,
    SendReceiveOptions options)

The first part of the question is that I need to create a handler dynamically for the first call because I only know the type at run time via configuration. I tried using reflection but I keep on getting ambigiousmethod exceptions

The second part of the question is that in the dynamically generated handler, I need to generate a strongly typed event for the received information.

The last part of the question is that another part of the system has to wire up to receive the strongly typed event which again is only known at run time

Any help is greatly appreciated.

My attempt at reflection is below , I was trying to use the information in the two links above along with some googling Builds a Delegate from MethodInfo? and Generic Method Executed with a runtime type to figure out the way to do it

        MethodInfo method = typeof(Connection).GetMethod("AppendIncomingPacketHandler"); //this generates an ambigious method exception due to two functions being available

        MethodInfo generic = method.MakeGenericMethod(configuration.TypeToListenTo);
        Delegate.CreateDelegate(typeof(NetworkComms.PacketHandlerCallBackDelegate<>)) //cant figure out how to create the typed delegate and pass it to the right function.

I know you can specify which function to call by passing in the parameters in the event of an ambiguous method exception but the problem is that the arguments as seen above require a typed delegate as well.

Thanks for reading

//Building the code up from comments received so far I have

        var methods = typeof(Connection).GetMethods();
        var functionOfInterest = methods[21];
        var genericDelegate = typeof(NetworkComms.PacketHandlerCallBackDelegate<>);
        var constructedDelegate = genericDelegate.MakeGenericType(new Type[] { configuration.TypeToListenTo });

        DisplayTypeInfo(constructedDelegate);
        var mappedMethod  = functionOfInterest.MakeGenericMethod(configuration.TypeToListenTo);
        mappedMethod.Invoke(CommunicationLink,
            new object[] {configuration.TypeToListenTo.ToString(), constructedDelegate});

I now get this exception on the mappedMethod call...

Object of type 'System.RuntimeType' cannot be converted to type 'NetworkCommsDotNet.NetworkComms+PacketHandlerCallBackDelegate`1[NetworkCommunicationsTest.Program+Test

///after a bit more thinking

    var methods = typeof(Connection).GetMethods();
    var functionOfInterest = methods[21];
    var genericDelegate = typeof(NetworkComms.PacketHandlerCallBackDelegate<>);
    var constructedDelegate = genericDelegate.MakeGenericType(new Type[] { configuration.TypeToListenTo });

    //Delegate.CreateDelegate(constructedDelegate, func);
    DisplayTypeInfo(constructedDelegate);
    var mappedMethod = functionOfInterest.MakeGenericMethod(configuration.TypeToListenTo);

    var dynamicMethod = new DynamicMethod("dataHandler", null,
        new Type[] {typeof (PacketHeader), typeof (Connection), configuration.TypeToListenTo});

    ILGenerator il = dynamicMethod.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0); //random il just to test the concept
    il.Emit(OpCodes.Conv_I8); //random il just to test the concept
    il.Emit(OpCodes.Dup); //random il just to test the concept
    il.Emit(OpCodes.Mul); //random il just to test the concept
    il.Emit(OpCodes.Ret); //random il just to test the concept

    mappedMethod.Invoke(CommunicationLink,
        new object[] { configuration.TypeToListenTo.ToString(), dynamicMethod.CreateDelegate(constructedDelegate) });

Am I on the right track?

I have written the code below to hopefully better illustrate what I want to achieve, the bits of interest are commented out

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var thirdPartyConsumer = new ThirdPartyConsumer();
            thirdPartyConsumer.Start(typeof(string));
            var eventSubscriber = new EventSubscriber(thirdPartyConsumer, typeof (string));
        }

        public class ThirdParty
        {
            public delegate void CallBackDelegate<incomingObjectType>(incomingObjectType incomingObject);

            public delegate void CallBackSubscriberDelegate<incomingObjectType>();

            public void RegisterHandler<incomingType>(string name, CallBackDelegate<incomingType> callback)
                where incomingType : new()
            {
                Console.WriteLine("Registered type is {0}", typeof(incomingType));
                callback.Invoke(new incomingType());
            }

            public void RegisterSubscriber<incomingType>(string name, CallBackSubscriberDelegate<incomingType> callback)
            {
                Console.WriteLine("Registered type is {0}", typeof(incomingType));
                callback.Invoke();
            }
        }

        public class ThirdPartyConsumer
        {
            public void Start(Type dataType)
            {
                var thirdParty = new ThirdParty();

                // want to create a typed delegate to invoke the instance Callback<T> method
                //thirdParty.RegisterHandler(dataType.ToString(),Callback<dataType>); 

                // want to create a typed delegate to invoke the instance Callback<T> method
                //thirdParty.RegisterSubscriber(dataType.ToString(), Callback<dataType>);


                //want to create a public eventhandler on this object which is typed to datatype
                //CreateTypedEventHandler(dataType);
            }

            private void Callback()
            {
                Console.WriteLine("Called Callback");
            }


            private void Callback<T>(T incomingType)
            {
                Console.WriteLine("Called Generic Callback");

            }
        }

        public class EventSubscriber
        {
            public EventSubscriber(ThirdPartyConsumer consumer,Type  type)
            {
                //want to wire the dynamically created/added event handler
               //consumer.TypedEventHandler += ReceivedEvent();
            }

            private void ReceivedEvent<T>(T data)
            {
                Console.WriteLine("Event received of type {0}", typeof(T));
            }
        }

    }
}

//////WITH FEEDBACK FROM ANTON IVE GOT THIS NOW. Are there any problems with these approach especially performance wise? Is there a better way to do this?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var genericType = typeof(ThirdPartyConsumer<>);
            Type constructedGenericType = genericType.MakeGenericType(new Type[] { typeof(string) });

            var constructed = Activator.CreateInstance(constructedGenericType);

            MethodInfo castMethod = typeof(Utils).GetMethod("Cast").MakeGenericMethod(constructedGenericType);
            var cast = castMethod.Invoke(null, new object[] { constructed });

            var eventSubscriber = new EventSubscriber();
            MethodInfo subscribeMethod = typeof(EventSubscriber).GetMethod("Subscribe").MakeGenericMethod(new Type[] { typeof(string) });
            subscribeMethod.Invoke(eventSubscriber, new object[] { cast });
        }

        public class ThirdParty
        {
            public delegate void CallBackDelegate<incomingObjectType>(incomingObjectType incomingObject);

            public delegate void CallBackSubscriberDelegate<incomingObjectType>();

            public void RegisterHandler<incomingType>(string name, CallBackDelegate<incomingType> callback)
                where incomingType : new()
            {
                Console.WriteLine("Registered type is {0}", typeof(incomingType));
                callback.Invoke(new incomingType());
            }

            public void RegisterSubscriber<incomingType>(string name, CallBackSubscriberDelegate<incomingType> callback)
            {
                Console.WriteLine("Registered type is {0}", typeof(incomingType));
                callback.Invoke();
            }
        }

        public class ThirdPartyConsumer<T>
        {
            public event Action<T> TypedEventHandler;
            public void Start<T>() where T : new()
            {
                var thirdParty = new ThirdParty();

                // want to create a typed delegate to invoke the instance Callback<T> method
                thirdParty.RegisterHandler<T>(typeof(T).ToString(), Callback<T>);

                // want to create a typed delegate to invoke the instance Callback<T> method
                //thirdParty.RegisterSubscriber<T>(typeof (T).ToString(), Callback<T>);

            }



            private void Callback<T>(T incomingType)
            {
                Console.WriteLine("Called Generic Callback");

            }
        }

        public class EventSubscriber
        {
            public EventSubscriber()
            {

            }

            public void Subscribe<T>(ThirdPartyConsumer<T> consumer)
            {
                consumer.TypedEventHandler += consumer_TypedEventHandler;
            }

            void consumer_TypedEventHandler<T>(T obj)
            {

            }



        }

        public static class Utils
        {
            public static T Cast<T>(object o)
            {
                return (T)o;
            }
        }
    }
}
Community
  • 1
  • 1
Bernard
  • 995
  • 2
  • 9
  • 20
  • 1
    Show us your attempt at reflection – Yuval Itzchakov Jul 26 '14 at 09:07
  • Added what I was trying to do @YuvalItzchakov – Bernard Jul 26 '14 at 14:36
  • Use `GetMethods` and choose the correct overload manually, e.g. by number of method parameters. To create the closed generic type, use `type.MakeGenericType()`. – Anton Tykhyy Jul 26 '14 at 15:13
  • @AntonTykhyy thanks for the comment, added some more code,dont know if thats what you had in mind? Trying to do the same for the method call to see if it works – Bernard Jul 26 '14 at 15:30
  • You're moving in the right direction, although relying on the order of methods in the result of `GetMethods` is not OK in production code. Now think about what that exception message is telling you. Hint: is a delegate *type* the same as the delegate? – Anton Tykhyy Jul 26 '14 at 16:09
  • @AntonTykhyy thanks for the tip, its going past that section now, does that mean that I need to write IL (which I havent had the pleasure of before) to get this to work? Or is there another way to do it? – Bernard Jul 26 '14 at 18:29
  • Not necessarily, this depends on what is your handler going to be. If you already have a handler method somewhere with a signature compatible with `constructedDelegate` (this method may not be generic itself, consider `Action`), then just go ahead and use `CreateDelegate`. In other cases things get more complicated, including IL generation. What's your actual use case? – Anton Tykhyy Jul 26 '14 at 19:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58072/discussion-between-bernard-and-anton-tykhyy). – Bernard Jul 26 '14 at 19:42
  • Added sample so its clearer. @jbtule saw your answer http://stackoverflow.com/questions/18687033/how-to-create-a-dynamic-delegate-object-by-type-in-c. Thought I would tag you in case you had any ideas? – Bernard Jul 29 '14 at 18:40

1 Answers1

0

I went down the route suggested by @Anton which is the last example in the question. Along with FasterFlect and a judicious use of the dynamic keyword along with separate interface for the non generic and generic sections of the code, I have got a working solution which works fast enough for my needs.

Thanks everyone for reading

Bernard
  • 995
  • 2
  • 9
  • 20