Location>code7788 >text

C# Reflection to call differently-named generic methods

Popularity:984 ℃/2024-07-27 15:06:24

summarize

Due to work requirements, there is a need to control where the method goes by data type and method name
There are 8 data types used (string, Int16, Int32, Int64, Boolean, Byte, Single, Double).
There are only 11 methods for reading (generic methods with the same parameters but different data and generic return values) for the time being, but surely they will be added later!

The original plan was to arrange the combinations and write 88 lines of code, but it was always felt that there was too much duplicate code, and the subsequent maintenance was extremely tedious
For example, if you add a new read method, you need to add 8 lines of data type selection code, which is cumbersome, not to mention that it's easy to make mistakes.

A quick search on the web led me to reflection, which solved my problem perfectly, and now I'd like to share this reflection with you:

permutation (i.e. combination of items in a list)

That's right. I started out with permutations and combinations.


int datatype = default(int) ; // Decision value type
int GetType = default(int) ; // Decide by what method to read

//Type Selection
switch (datatype)
{
    case 2: res[0] += "'" + (ReadString(dataaddress , datalen , gettype)) + "',"; break;
    case 4: res[0] += (ReadInt(dataaddress , datalen , gettype)) + ","; break;
    case 6: res[0] += "'" + (ReadString(dataaddress , datalen , gettype)) + "',"; break;
    case 7: res[0] += (ReadUshort(dataaddress , datalen , gettype)) + ","; break;
    case 8: res[0] += (ReadUint(dataaddress , datalen , gettype)) + ","; break;
    case 9: res[0] += (ReadULong(dataaddress , datalen , gettype)) + ","; break;
    case 10: res[0] += (ReadInt(dataaddress , datalen , gettype)) + ","; break;
    case 11: res[0] += (ReadShort(dataaddress , datalen , gettype)) + ","; break;
    case 12: res[0] += (ReadByte(dataaddress , datalen , gettype)) + ","; break;
    case 13: res[0] += (ReadFloat(dataaddress , datalen , gettype)) + ","; break;
    case 14: res[0] += (ReadDouble(dataaddress , datalen , gettype)) + ","; break;
    case 15: res[0] += (ReadDouble(dataaddress , datalen , gettype)) + ","; break;
    case 20: res[0] += (ReadBool(dataaddress , datalen , gettype)).ToLower() + ","; break;
    case 31: res[0] += (ReadLong(dataaddress , datalen , gettype)) + ","; break;
    default: res[0] += (ReadUshort(dataaddress , datalen , gettype)) + ","; break;
}
//Methodological choices
//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);
    }
}
......(I won't list them all.,permutation (i.e. combination of items in a list),You know what I'm talking about.?)

Maybe you found some anomaly and feel that I'm not writing it correctly, I should control the method first, and then the value type, but, it makes no difference, it's still permutations and combinations, just decentralized

It's not hard to see that the above code is very much duplicated, almost like copying a copy and then changing the generalization passed into the

So I wondered if I could just convert the parameters to generics and fill them in, and then obviously that didn't work, and then I found thereflex (i.e. automatic reaction of organism)This magic weapon.

Reflections (positive start)

int datatype = default(int) ; // Determines the value type.
int GetType = default(int) ; // Determines the method by which the value is read.

// method name
string methodName = "ModbusTcpRead"; // determine what method to read by.
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 = "OmronFinsNetRead"; break
    case 11: methodName = "MelsecFxSerialOverTcpRead"; break;
    case 12: methodName = "KeyenceMcAsciiNetRead"; break;
    default: methodName = "ModbusTcpRead"; break;
}
// Data Value Type
string type = "System.
switch (datatype)
case 2: type = ""; break
    case 2: type = """; break;
    case 4: type = "System.
    case 4: type = "System.Int32"; break; case 6: type = """; break;
    case 7: type = "System.
    case 8: type = "System.UInt32"; break; case 9: type = "System.
    case 9: type = "System.
    case 10: type = "System.UInt32"; break; case 11: type = "System.
    case 11: type = "System.
    case 12: type = """; break;
    case 13: type = ""; break; //float
    case 14: type = ""; break; //float
    case 15: type = ""; break; //float
    case 20: type = ""; break; //float.
    case 31: type = "System.
    default: type = "System.
}
MethodInfo method = typeof(PLCOper).GetMethod(methodName , | ); }
MethodInfo genericMethod = ((type , false)); } methodInfo method = typeof(PLCOper).
object result = (this , new object[] { dataaddress , datalen }));

// There are a couple of points to note here
///1, typeof(PLCOper) The class name in parentheses must be the name of the parent class of the calling method.
/ / 2, GetMethod the second parameter, the former is used to filter the properties of the method, such as static or non-static, my method is non-static, so you need to Parameters
//3, Invoke the first parameter, if you call a static method, pass null, the method within the instance, you need to pass this
//4, Invoke the second parameter, is the method of the entry parameter

Isn't it very much more concise? (It doesn't seem to make a difference maybe because I didn't write out all the permutations?)

In the future, you only need to change the name of a new method once.

It's perfect!

close

Thanks for seeing this.