The high level problem I'm having in C# is to make a single copy of a data structure that describes a robot control network packet (Ethercat), and then to use that single data structure to extract data from a collection of packets.
The problem arises when attempting to use the data from the accumulated packets as there is implicit duplication of the data structure with casting or calling functions that specify the type. To assist in explaining the goal, I've written a python program that does what I want and would like help to determine if its possible to do this in C#.
The challenge for me in C# is the single function "get_vector" which returns a homogeneous collection of a variable numerical type. This type is defined in the packet structure and in python can be used without defining re-defining the data structure.
import struct# description of the complete packet
class PACKET_STRUCTURE :# given a field name and a list of packets, return a vector
# this is the function that seems impossible in C# because the type of what is returned changes
def get_vector(self, name, packet_list):# locate the packet definition by the name of the vectorresult = [x for x in self.packet_def if x.field_name == name]# without error checking, pos contains the location of the definitionpos = result[0].position;# decode ALL the pacckets in the (encoded) packet list - returning a list of [time_sec, status, position# in C# this step is similar to using Marshal.PtrToStructure to transform from byte[] to a structdecoded_packet_list = [struct.unpack(self.fmt_str, packet) for packet in packet_list];# from the list of decoded_packets, extract the desired field into its own list vector = [decode[pos] for decode in decoded_packet_list]# in C# this is similar to:# var CS_vector = decode_packet_list.Select(item => item.field_name).ToArray();# so far in C# there is no duplication of the packet structure.# but after this point, assume I cast CS_vector to object and return it - # to use the object, I've not figured out how to avoid casting it to some type of array# eg double[], int32[] return vector def __init__(self):self.packet_def = list();self.fmt_str = "<";self.cnt = 0;# add description of single item to the structuredef add(self, struct_def) :struct_def.position = len(self.packet_def);self.packet_def.append(struct_def);self.fmt_str += struct_def.type; # create a simple packet based on a counter based on the defined structuredef make_packet(self):vals = [self.cnt*10+x for x in range(0, len(self.packet_def))];self.cnt += 1;pk = apply(struct.pack, [self.fmt_str] + vals)# print len(pk), ["%c" % x for x in pk]return pkdef get_names(self):return [packet_items.field_name for packet_items in self.packet_def];# the description of a single field within the packet
class PACKET_ITEM :def __init__(self, field_name, type):self.field_name = field_nameself.type = type;# self.offset = 0;self.position = 0;if __name__ == "__main__" :INT32 = "l";UINT16 = "H";FLOAT = "f";packet_def = PACKET_STRUCTURE();# create an example packet structure - which is arbituary and could be anything - it could even be read from a file# this definition is the ONLY defintion of the packet structure# changes here require NO changes elsewhere in the programpacket_def.add(PACKET_ITEM("time_sec", FLOAT))packet_def.add(PACKET_ITEM ("status",UINT16))packet_def.add(PACKET_ITEM ("position",INT32))# create a list of packetspk_list = list()for cnt in range(0,10) :pk_list.append(packet_def.make_packet());################################# get the vectors without replicating the structure# eg no int32[] position = (int32[])get_vector()name_list = packet_def.get_names();for name in name_list :vector = packet_def.get_vector(name, pk_list);print name, vector