C# 通过反射(Reflection)调用不同名泛型方法

  • C# 通过反射(Reflection)调用不同名泛型方法已关闭评论
  • 39 次浏览
  • A+
所属分类:.NET技术
摘要

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


概述

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

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

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

排列组合

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

 int datatype = default(int) ; // 决定值类型 int GetType = default(int) ; // 决定通过什么方法读取  //类型选择 switch (datatype) {     case 2: res[0] += "'" + Convert.ToString(ReadString(dataaddress , datalen , gettype)) + "',"; break;     case 4: res[0] += Convert.ToString(ReadInt(dataaddress , datalen , gettype)) + ","; break;     case 6: res[0] += "'" + Convert.ToString(ReadString(dataaddress , datalen , gettype)) + "',"; break;     case 7: res[0] += Convert.ToString(ReadUshort(dataaddress , datalen , gettype)) + ","; break;     case 8: res[0] += Convert.ToString(ReadUint(dataaddress , datalen , gettype)) + ","; break;     case 9: res[0] += Convert.ToString(ReadULong(dataaddress , datalen , gettype)) + ","; break;     case 10: res[0] += Convert.ToString(ReadInt(dataaddress , datalen , gettype)) + ","; break;     case 11: res[0] += Convert.ToString(ReadShort(dataaddress , datalen , gettype)) + ","; break;     case 12: res[0] += Convert.ToString(ReadByte(dataaddress , datalen , gettype)) + ","; break;     case 13: res[0] += Convert.ToString(ReadFloat(dataaddress , datalen , gettype)) + ","; break;     case 14: res[0] += Convert.ToString(ReadDouble(dataaddress , datalen , gettype)) + ","; break;     case 15: res[0] += Convert.ToString(ReadDouble(dataaddress , datalen , gettype)) + ","; break;     case 20: res[0] += Convert.ToString(ReadBool(dataaddress , datalen , gettype)).ToLower() + ","; break;     case 31: res[0] += Convert.ToString(ReadLong(dataaddress , datalen , gettype)) + ","; break;     default: res[0] += Convert.ToString(ReadUshort(dataaddress , datalen , gettype)) + ","; break; } //方法选择 //string public string ReadString(string StartAddress , int Length , int GetType) {     switch (GetType)     {         case 1: return ModbusTcpRead<string>(StartAddress , Length);         case 2: return ModbusRtuRead<string>(StartAddress , Length);         case 3: return ModbusRtuOverTcpRead<string>(StartAddress , Length);         case 5: return InovanceTcpNetRead<string>(StartAddress , Length);         case 6: return KeyenceMcNetRead<string>(StartAddress , Length);         case 7: return MelsecMcNetRead<string>(StartAddress , Length);         case 8: return OmronFinsNetRead<string>(StartAddress , Length);         case 9: return PanasonicMcNetRead<string>(StartAddress , Length);         case 10: return SiemensS7NetRead<string>(StartAddress , Length);         case 11: return MelsecFxSerialOverTcpRead<string>(StartAddress , Length);         case 12: return KeyenceMcAsciiNetRead<string>(StartAddress , Length);         default: return ModbusTcpRead<string>(StartAddress , Length);     } } //Bool public bool ReadBool(string StartAddress , int Length , int GetType) {     switch (GetType)     {         case 1: return ModbusTcpRead<bool>(StartAddress , Length);         case 2: return ModbusRtuRead<bool>(StartAddress , Length);         case 3: return ModbusRtuOverTcpRead<bool>(StartAddress , Length);         case 5: return InovanceTcpNetRead<bool>(StartAddress , Length);         case 6: return KeyenceMcNetRead<bool>(StartAddress , Length);         case 7: return MelsecMcNetRead<bool>(StartAddress , Length);         case 8: return OmronFinsNetRead<bool>(StartAddress , Length);         case 9: return PanasonicMcNetRead<bool>(StartAddress , Length);         case 10: return SiemensS7NetRead<bool>(StartAddress , Length);         case 11: return MelsecFxSerialOverTcpRead<bool>(StartAddress , Length);         case 12: return KeyenceMcAsciiNetRead<bool>(StartAddress , Length);         default: return ModbusTcpRead<bool>(StartAddress , Length);     } } ......(就不全部列出来了,排列组合,懂得吧?) 

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

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

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

反射(正片开始)

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

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

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

非常完美!

结束

感谢看到这里。