经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
C# 通过反射(Reflection)调用不同名泛型方法
来源:cnblogs  作者:HookDing  时间:2024/7/29 9:30:12  对本文有异议

概述

由于工作需要,需要通过数据类型和方法名控制方法走向
用到的数据类型有8种(string,Int16,Int32,Int64,Boolean,Byte,Single,Double)
读取的方法(参数一致,但是数据不同的泛型方法,返回值也是泛型)暂时只有11种,但肯定的是,后续一定会增加

原本计划排列组合,写个88行代码,但是总觉得重复代码过多,且后续维护极其繁琐
例如:新增一个读取方法,需要额外新增8行数据类型选择代码,繁琐暂且不说,主要是容易出现纰漏

网络上一翻搜寻,找到了反射,完美解决了我的问题,现在想把这个反射分享给大家:

排列组合

没错,我最开始就是排列组合

  1. int datatype = default(int) ; // 决定值类型
  2. int GetType = default(int) ; // 决定通过什么方法读取
  3. //类型选择
  4. switch (datatype)
  5. {
  6. case 2: res[0] += "'" + Convert.ToString(ReadString(dataaddress , datalen , gettype)) + "',"; break;
  7. case 4: res[0] += Convert.ToString(ReadInt(dataaddress , datalen , gettype)) + ","; break;
  8. case 6: res[0] += "'" + Convert.ToString(ReadString(dataaddress , datalen , gettype)) + "',"; break;
  9. case 7: res[0] += Convert.ToString(ReadUshort(dataaddress , datalen , gettype)) + ","; break;
  10. case 8: res[0] += Convert.ToString(ReadUint(dataaddress , datalen , gettype)) + ","; break;
  11. case 9: res[0] += Convert.ToString(ReadULong(dataaddress , datalen , gettype)) + ","; break;
  12. case 10: res[0] += Convert.ToString(ReadInt(dataaddress , datalen , gettype)) + ","; break;
  13. case 11: res[0] += Convert.ToString(ReadShort(dataaddress , datalen , gettype)) + ","; break;
  14. case 12: res[0] += Convert.ToString(ReadByte(dataaddress , datalen , gettype)) + ","; break;
  15. case 13: res[0] += Convert.ToString(ReadFloat(dataaddress , datalen , gettype)) + ","; break;
  16. case 14: res[0] += Convert.ToString(ReadDouble(dataaddress , datalen , gettype)) + ","; break;
  17. case 15: res[0] += Convert.ToString(ReadDouble(dataaddress , datalen , gettype)) + ","; break;
  18. case 20: res[0] += Convert.ToString(ReadBool(dataaddress , datalen , gettype)).ToLower() + ","; break;
  19. case 31: res[0] += Convert.ToString(ReadLong(dataaddress , datalen , gettype)) + ","; break;
  20. default: res[0] += Convert.ToString(ReadUshort(dataaddress , datalen , gettype)) + ","; break;
  21. }
  22. //方法选择
  23. //string
  24. public string ReadString(string StartAddress , int Length , int GetType)
  25. {
  26. switch (GetType)
  27. {
  28. case 1: return ModbusTcpRead<string>(StartAddress , Length);
  29. case 2: return ModbusRtuRead<string>(StartAddress , Length);
  30. case 3: return ModbusRtuOverTcpRead<string>(StartAddress , Length);
  31. case 5: return InovanceTcpNetRead<string>(StartAddress , Length);
  32. case 6: return KeyenceMcNetRead<string>(StartAddress , Length);
  33. case 7: return MelsecMcNetRead<string>(StartAddress , Length);
  34. case 8: return OmronFinsNetRead<string>(StartAddress , Length);
  35. case 9: return PanasonicMcNetRead<string>(StartAddress , Length);
  36. case 10: return SiemensS7NetRead<string>(StartAddress , Length);
  37. case 11: return MelsecFxSerialOverTcpRead<string>(StartAddress , Length);
  38. case 12: return KeyenceMcAsciiNetRead<string>(StartAddress , Length);
  39. default: return ModbusTcpRead<string>(StartAddress , Length);
  40. }
  41. }
  42. //Bool
  43. public bool ReadBool(string StartAddress , int Length , int GetType)
  44. {
  45. switch (GetType)
  46. {
  47. case 1: return ModbusTcpRead<bool>(StartAddress , Length);
  48. case 2: return ModbusRtuRead<bool>(StartAddress , Length);
  49. case 3: return ModbusRtuOverTcpRead<bool>(StartAddress , Length);
  50. case 5: return InovanceTcpNetRead<bool>(StartAddress , Length);
  51. case 6: return KeyenceMcNetRead<bool>(StartAddress , Length);
  52. case 7: return MelsecMcNetRead<bool>(StartAddress , Length);
  53. case 8: return OmronFinsNetRead<bool>(StartAddress , Length);
  54. case 9: return PanasonicMcNetRead<bool>(StartAddress , Length);
  55. case 10: return SiemensS7NetRead<bool>(StartAddress , Length);
  56. case 11: return MelsecFxSerialOverTcpRead<bool>(StartAddress , Length);
  57. case 12: return KeyenceMcAsciiNetRead<bool>(StartAddress , Length);
  58. default: return ModbusTcpRead<bool>(StartAddress , Length);
  59. }
  60. }
  61. ......(就不全部列出来了,排列组合,懂得吧?)

或许你发现了什么异常,感觉我这么写不太对,应该先控制方法,在控制值类型,但,没区别,还是排列组合,只不过分散了而已

以上代码也不难看出,重复代码非常多,几乎就是copy一份,然后改一下泛型传入

所以我在想,能不能吧参数转换成泛型填入,然后显然不行,后来找到了反射这个法宝

反射(正片开始)

  1. int datatype = default(int) ; // 决定值类型
  2. int GetType = default(int) ; // 决定通过什么方法读取
  3. //方法名
  4. string methodName = "ModbusTcpRead";
  5. switch (gettype)
  6. {
  7. case 1: methodName = "ModbusTcpRead"; break;
  8. case 2: methodName = "ModbusRtuRead"; break;
  9. case 3: methodName = "ModbusRtuOverTcpRead"; break;
  10. case 5: methodName = "InovanceTcpNetRead"; break;
  11. case 6: methodName = "KeyenceMcNetRead"; break;
  12. case 7: methodName = "MelsecMcNetRead"; break;
  13. case 8: methodName = "OmronFinsNetRead"; break;
  14. case 9: methodName = "PanasonicMcNetRead"; break;
  15. case 10: methodName = "SiemensS7NetRead"; break;
  16. case 11: methodName = "MelsecFxSerialOverTcpRead"; break;
  17. case 12: methodName = "KeyenceMcAsciiNetRead"; break;
  18. default: methodName = "ModbusTcpRead"; break;
  19. }
  20. //数据值类型
  21. string type = "System.Int32";
  22. switch (datatype)
  23. {
  24. case 2: type = "System.String"; break;
  25. case 4: type = "System.Int32"; break;
  26. case 6: type = "System.String"; break;
  27. case 7: type = "System.UInt16"; break;
  28. case 8: type = "System.UInt32"; break;
  29. case 9: type = "System.UInt64"; break;
  30. case 10: type = "System.Int32"; break;
  31. case 11: type = "System.Int16"; break;
  32. case 12: type = "System.Byte"; break;
  33. case 13: type = "System.Single"; break;//float
  34. case 14: type = "System.Double"; break;
  35. case 15: type = "System.Double"; break;
  36. case 20: type = "System.Boolean"; break;
  37. case 31: type = "System.Int64"; break;
  38. default: type = "System.UInt16"; break;
  39. }
  40. MethodInfo method = typeof(PLCOper).GetMethod(methodName , BindingFlags.Instance | BindingFlags.Public);
  41. MethodInfo genericMethod = method.MakeGenericMethod(Type.GetType(type , false));
  42. object result = genericMethod.Invoke(this , new object[] { dataaddress , datalen });
  43. //这里有几点要提醒
  44. //1、typeof(PLCOper) 括号里的类名必须是调用方法的父类名
  45. //2、GetMethod 第二个参数,前者用于过滤方法的属性,比如是静态还是非静态,我方法全是非静态,所以需要BindingFlags.Instance 参数
  46. //3、Invoke 第一个参数,如果调用静态方法,传入null就好,实例内的方法,需要传入this
  47. //4、Invoke 第二个参数,是方法的入参

是不是简洁非常多?(看起来没区别或许是因为排列组合我没全部写出来?)

以后新增方法名也只需要在这里改一次就可以了

非常完美!

结束

感谢看到这里。

原文链接:https://www.cnblogs.com/HookDing/p/18326960

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号