动态委托和事件创建

时间:2014-07-26 09:02:06

标签: c# dynamic

我见过以下问题Generating Delegate Types dynamically in C#How to create a dynamic delegate object by type in C#?,我担心我还没有完全理解这些概念。

我试图解决的问题是:第三方库提供以下功能

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

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

问题的第一部分是我需要为第一次调用动态创建一个处理程序,因为我只通过配置知道运行时的类型。我尝试使用反射,但我继续得到ambigiousmethod例外

问题的第二部分是在动态生成的处理程序中,我需要为接收到的信息生成强类型事件。

问题的最后一部分是系统的另一部分必须连接以接收强类型事件,该事件仅在运行时才知道

非常感谢任何帮助。

我的反思尝试如下,我试图使用上面两个链接中的信息以及一些谷歌搜索Builds a Delegate from MethodInfo?Generic Method Executed with a runtime type 找出实现方法

        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.

我知道你可以通过在模糊方法异常的情况下传入参数来指定调用哪个函数,但问题是上面的参数也需要一个类型化的委托。

感谢您阅读

//从目前为止收到的评论构建代码

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

我现在在mappedMethod调用...

上得到此异常

'System.RuntimeType'类型的对象无法转换为类型'NetworkCommsDotNet.NetworkComms + PacketHandlerCallBackDelegate`1 [NetworkCommunicationsTest.Program + Test

///经过多思考后

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

我是在正确的轨道上吗?

我已经编写了下面的代码,希望更好地说明我想要实现的目标,感兴趣的部分被注释掉

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

    }
}

//////与ANTON的反馈我现在得到了。这些方法是否存在任何问题,尤其是性能方面?有更好的方法吗?

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

1 个答案:

答案 0 :(得分:0)

我走了@Anton建议的路线,这是问题中的最后一个例子。除了FasterFlect和明智地使用动态关键字以及代码的非通用和通用部分的单独界面外,我还有一个工作解决方案,可以快速满足我的需求。

感谢大家阅读