Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用“通用处理程序生成器”时的C方法解析惊喜_C#_Generics - Fatal编程技术网

C# 使用“通用处理程序生成器”时的C方法解析惊喜

C# 使用“通用处理程序生成器”时的C方法解析惊喜,c#,generics,C#,Generics,今天我偶然发现了一个问题,我无法向自己解释。我试图构建一个通用处理程序生成器,以清理项目中的重复代码。我认为这可以很容易地通过一些泛型和行动的力量来实现 我提出了一个类似的解决方案,这是一个简化的版本来说明问题: 使用制度; 命名空间GenericationBuilder{ 公共类第一条消息{} 公共类MessageHandler{ 公共无效HandleMessageobject消息 =>Console.WriteLineFallback对象处理程序; 公共无效HandleMessageFirs

今天我偶然发现了一个问题,我无法向自己解释。我试图构建一个通用处理程序生成器,以清理项目中的重复代码。我认为这可以很容易地通过一些泛型和行动的力量来实现

我提出了一个类似的解决方案,这是一个简化的版本来说明问题:

使用制度; 命名空间GenericationBuilder{ 公共类第一条消息{} 公共类MessageHandler{ 公共无效HandleMessageobject消息 =>Console.WriteLineFallback对象处理程序; 公共无效HandleMessageFirstMessage消息消息 =>Console.WriteLineFirstMessage处理程序; } 班级计划 { 公共静态操作BuildHandler{ 动作处理程序=msg=>{ 使用Type={msg.GetType.Name}调用Console.WriteLine$; var messageHandler=newmessagehandler; messageHandler.HandleMessagemsg; }; 返回处理程序; } 静态环[]args { //这就是惊喜 var generatedHandler=BuildHandler; var msg=新的第一条消息; WriteLine$调用类型为{msg.GetType.Name}的生成处理程序; 生成HandlerMsg; //这给出了预期的行为 var myHandler=newmessagehandler; myHandler.HandleMessagemsg; } } } 输出:

Calling generated handler with type=FirstMessage
Called with Type=FirstMessage
Fallback object handler
FirstMessage handler
当然,当我用手头的FirstMessage对象调用HandleMessage时,C会选择最匹配的重载:HandleMessageFirstMessage。如果不使用通用处理程序生成器,就会发生这种情况

即使在生成的处理程序中,msg的类型仍然是FirstMessage。但是call handler.handleMessagesG仍然会使用对象签名触发回退方法

谁能给我解释一下吗

C将选择最匹配的重载

是的,但它将在编译时执行,而不是基于C编译器可以从代码中获取的类型信息的运行时

您的处理程序有一个泛型参数,但该参数不受任何条件的限制,因此,它可以是任何类型:FirstMessage、object甚至Program等等,然后知道这一点,编译器将选择最佳匹配重载,这显然是HandleMessageobject,因为它可以接受任何提供的类型。要快速检查它,您可以为消息创建基类/接口消息,并将泛型参数限制为:where MessageType:Message,并在MessageHandler类中提供适当的方法,您将看到编译器将选择HandleMessageMessage而不是HandleMessageobject


因此,您可以尝试实现visitor double dispatch模式来解决这个问题,我假设您有更多的消息类型。

哦,这让我感到惊讶:使用泛型参数强制C在编译时连接方法?我不知道这件事。但这将清楚地表明:@甘地:它的工作原理与常用参数相同。如果只创建一个方法而不是操作委托,如:Handlerobject msg{messageHandler.HandleMessageMgemsG;},即使传递FirstMessage类型,它也会选择HandleMessageobject,因为调用哪个方法是在编译时确定的。@ghandi-除非使用动态或其他形式的后期绑定,重载解析总是在编译时发生,不管是否为泛型。编译器将发出一个标识其所选特定方法的标记。