【问题标题】:Dynamic delegate and event creation动态委托和事件创建
【发布时间】:2014-08-14 17:57:09
【问题描述】:

我已经看到以下问题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)

问题的第一部分是我需要为第一次调用动态创建一个处理程序,因为我只在运行时通过配置知道类型。我尝试使用反射,但我不断收到模棱两可的方法异常

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

问题的最后一部分是系统的另一部分必须连接起来才能接收强类型事件,而这又是仅在运行时才知道的

非常感谢任何帮助。

我的反思尝试如下,我试图使用上面两个链接中的信息以及一些谷歌搜索 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.

我知道您可以在发生模棱两可的方法异常时通过传入参数来指定要调用的函数,但问题是上面看到的参数也需要类型化委托。

感谢阅读

//从目前收到的 cmets 构建代码

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

【问题讨论】:

  • 向我们展示你的反思尝试
  • 添加了我想要做的事情@YuvalItzchakov
  • 使用GetMethods 并手动选择正确的重载,例如通过方法参数的数量。要创建封闭的泛型类型,请使用type.MakeGenericType()
  • @AntonTykhyy 感谢您的评论,添加了更多代码,不知道您是否想到了这些?尝试对方法调用做同样的事情,看看它是否有效
  • 您正朝着正确的方向前进,尽管在生产代码中依赖GetMethods 结果中的方法顺序是不可行的。现在想想那个异常消息告诉你什么。提示:委托type是否与委托相同?

标签: c# dynamic


【解决方案1】:

我沿着@Anton 建议的路线走,这是问题中的最后一个示例。除了 FasterFlect 和对 dynamic 关键字的明智使用以及代码的非泛型和泛型部分的单独接口之外,我还得到了一个工作解决方案,它的运行速度足以满足我的需要。

感谢大家阅读

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-16
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    相关资源
    最近更新 更多