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;
}
}
}
}