Home > front end >  How to filter only specified type in class dynamically in C#?
How to filter only specified type in class dynamically in C#?

Time:10-07

My English skill is poor because I'm not a native English speaker. please understand.

I will tell you about what I want detailly. I created a class below

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class TestClassForNetwork
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11), JsonIgnore]
        public byte[] field1;

        public short field2;
        public short field3;
        public short field4;
    }

As you know, when deserializing or serializing, I pay attention to converting to a specified endian. so I added the below code.

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class TestClassForNetwork
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11), JsonIgnore]
        public byte[] field1;

        public short field2;
        public short field3;
        public short field4;

        public void ToHostOrder()
        {
            if (!BitConverter.IsLittleEndian) return;

            field2 = IPAddress.NetworkToHostOrder(field2);
            field3 = IPAddress.NetworkToHostOrder(field3);
            field4 = IPAddress.NetworkToHostOrder(field4);
        }

        public void ToNetworkOrder()
        {
            if (!BitConverter.IsLittleEndian) return;

            field2 = IPAddress.HostToNetworkOrder(field2);
            field3 = IPAddress.HostToNetworkOrder(field3);
            field4 = IPAddress.HostToNetworkOrder(field4);
        }
    }

Here, I thought if it is added the field that has more 2byte, I have to modify ToHostOrder and ToNetworkOrder functions. and this will increase the cost of maintenance.

So I thought the idea was as below.

        public void ToHostOrder()
        {
            if (!BitConverter.IsLittleEndian) return;

            // filtering only short type in this class.
            FieldInfo[] shortFields;
            
            foreach(var shortField in shortFields)
                shortField = IPAddress.NetworkToHostOrder(shortField);

            // filtering only int type in this class.
            FieldInfo[] intFields;

            foreach(var intField in intFields)
                intField = IPAddress.NetworkToHostOrder(intField);
        }

        public void ToNetworkOrder()
        {
            if (!BitConverter.IsLittleEndian) return;

            // filtering only short type in this class.
            FieldInfo[] shortFields;
            
            foreach(var shortField in shortFields)
                shortField = IPAddress.HostToNetworkOrder(shortField);

            // filtering only int type in this class.
            FieldInfo[] intFields;

            foreach(var intField in intFields)
                intField = IPAddress.HostToNetworkOrder(intField);
        }

This idea seems to be poor if the count of fields in class is small because the readability is poor but I think this idea will decrease the cost of maintenance if the count of field is bigger because it is no need to worry to convert to a specified endian.

Could someone tell me how to realize this idea?

Thank you for reading.

CodePudding user response:

You can solve this using System.Reflection and getting all fields of a short type, and then using GetValue and SetValue to get and set the respective fields

In the constructor I set a List of all the fields, so it's only used once. Using System.Linq's Where makes sure we only get fields of short type

    public TestClassForNetwork()
    {
        shortFields = this.GetType().GetFields().Where(field => field.FieldType == typeof(short)).ToList();
    }
    public List<FieldInfo> shortFields = new List<FieldInfo>();

Taking the same sample fields you have

    public byte[] field1;
    public short field2;
    public short field3;
    public short field4;

You can implement ToHostOrder and ToNetworkOrder like this

    public void ToHostOrder()
    {
        if (!BitConverter.IsLittleEndian) return;

        foreach (var shortField in shortFields)
        {
            shortField.SetValue(this, IPAddress.NetworkToHostOrder((short)shortField.GetValue(this)));
        }

    }

    public void ToNetworkOrder()
    {
        if (!BitConverter.IsLittleEndian) return;

        foreach (var shortField in shortFields)
        {
            shortField.SetValue(this, IPAddress.NetworkToHostOrder((short)shortField.GetValue(this)));
        }
    }

Going forward, you should only need to add new short fields in your class, for it to be implemented in the methods

CodePudding user response:

you can use MemoryPack library and it can do it for you amazingly with higher performance and code readability.

  • It doesn't use reflection and all of the stuff is being generated in compile time.

  • It handles endian and other OS/CPU architecture stuff

  • It is being maintained by a strong open-source community

  • It's performance is 50X better than Json or ProtoBuff serialization

  • Related