using Newtonsoft.Json.Linq; using S7.Net.Types; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace BPASmartClient.S7Net { public static class EntityClassResolution { private static IEnumerable GetAccessableProperties(Type classType) { return from p in classType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty) where p.GetSetMethod() != null select p; } private static double GetIncreasedNumberOfBytes(double numBytes, Type type, PropertyInfo propertyInfo) { switch (type.Name) { case "Boolean": numBytes += 0.125; break; case "Byte": numBytes += 1.0; break; case "Int16": case "UInt16": case "Ushort": case "Short": numBytes += 2.0; break; case "Int32": case "UInt32": case "Single": case "float": numBytes += 4.0; break; case "Double": numBytes += 8.0; break; case "String": //numBytes += 256.0; double len = 256.0; if (propertyInfo.CustomAttributes.Count() > 0) { var tempLen = propertyInfo.GetCustomAttribute(); if (tempLen != null) len = Convert.ToDouble(tempLen.Len) + 2.0; } numBytes += len; break; default: numBytes = GetClassSize(Activator.CreateInstance(type), numBytes, isInnerProperty: true); if (type.IsClass) IncrementToEven(ref numBytes); break; } return numBytes; } /// /// 获取实体类的字节大小 /// /// /// /// /// /// public static double GetClassSize(object instance, double numBytes = 0.0, bool isInnerProperty = false) { foreach (PropertyInfo accessableProperty in GetAccessableProperties(instance.GetType())) { if (accessableProperty.PropertyType.IsArray) { Type elementType = accessableProperty.PropertyType.GetElementType(); Array array = (Array)accessableProperty.GetValue(instance, null); if (array.Length <= 0) { throw new Exception("Cannot determine size of class, because an array is defined which has no fixed size greater than zero."); } IncrementToEven(ref numBytes); for (int i = 0; i < array.Length; i++) { numBytes = GetIncreasedNumberOfBytes(numBytes, elementType, accessableProperty); } } else { numBytes = GetIncreasedNumberOfBytes(numBytes, accessableProperty.PropertyType, accessableProperty); } } if (!isInnerProperty) { numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } } return numBytes; } private static object? GetPropertyValue(Type propertyType, byte[] bytes, PropertyInfo propertyInfo, ref double numBytes) { object obj = null; switch (propertyType.Name) { case "Boolean": { int num = (int)Math.Floor(numBytes); int num2 = (int)((numBytes - (double)num) / 0.125); obj = (((bytes[num] & (int)Math.Pow(2.0, num2)) == 0) ? ((object)false) : ((object)true)); numBytes += 0.125; break; } case "Byte": numBytes = Math.Ceiling(numBytes); obj = bytes[(int)numBytes]; numBytes += 1.0; break; case "Int16": numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } obj = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]).ConvertToShort(); numBytes += 2.0; break; case "UInt16": numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } obj = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]); numBytes += 2.0; break; case "Int32": numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } obj = DWord.FromBytes(bytes[(int)numBytes + 3], bytes[(int)numBytes + 2], bytes[(int)numBytes + 1], bytes[(int)numBytes]).ConvertToInt(); numBytes += 4.0; break; case "UInt32": numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } obj = DWord.FromBytes(bytes[(int)numBytes], bytes[(int)numBytes + 1], bytes[(int)numBytes + 2], bytes[(int)numBytes + 3]); numBytes += 4.0; break; case "Single": numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } obj = Real.FromByteArray(new byte[4] { bytes[(int)numBytes], bytes[(int)numBytes + 1], bytes[(int)numBytes + 2], bytes[(int)numBytes + 3] }); numBytes += 4.0; break; case "Double": { numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } byte[] array = new byte[8]; Array.Copy(bytes, (int)numBytes, array, 0, 8); obj = LReal.FromByteArray(array); numBytes += 8.0; break; } case "String": //byte[] sarray = new byte[256]; //Array.Copy(bytes, (int)numBytes, sarray, 0, 256); //obj = GetGb2312()?.GetString(sarray).Trim().Replace(" ", "").Replace("\n", ""); //numBytes += 256.0; int len = 256; if (propertyInfo.CustomAttributes.Count() > 0) { var tempLen = propertyInfo.GetCustomAttribute(); if (tempLen != null) len = tempLen.Len + 2; } byte[] sarray = new byte[len]; Array.Copy(bytes, (int)numBytes, sarray, 0, len); List bytes1 = new List(); if (sarray.Length > 2) for (int i = 2; i < sarray.Length; i++) if (sarray[i] > 0) bytes1.Add(sarray[i]); obj = GetGb2312()?.GetString(bytes1.ToArray()).Trim().Replace(" ", "").Replace("\n", ""); numBytes += len; break; default: { object obj2 = Activator.CreateInstance(propertyType); numBytes = FromBytes(obj2, bytes, numBytes); numBytes = Math.Ceiling(numBytes); if (numBytes / 2.0 - Math.Floor(numBytes / 2.0) > 0.0) { numBytes += 1.0; } obj = obj2; break; } } return obj; } private static Encoding GetGb2312() { //获取指定的编码不存在的时候需要安装 System.Text.Encoding.CodePages nuget包 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); return Encoding.GetEncoding("gb2312"); } public static double FromBytes(object sourceClass, byte[] bytes, double numBytes = 0.0, bool isInnerClass = false) { if (bytes == null) { return numBytes; } foreach (PropertyInfo accessableProperty in GetAccessableProperties(sourceClass.GetType())) { if (accessableProperty.PropertyType.IsArray) { Array array = (Array)accessableProperty.GetValue(sourceClass, null); IncrementToEven(ref numBytes); Type elementType = accessableProperty.PropertyType.GetElementType(); for (int i = 0; i < array.Length; i++) { if (!(numBytes < (double)bytes.Length)) { break; } array.SetValue(GetPropertyValue(elementType, bytes, accessableProperty, ref numBytes), i); } } else { accessableProperty.SetValue(sourceClass, GetPropertyValue(accessableProperty.PropertyType, bytes, accessableProperty, ref numBytes), null); } } return numBytes; } private static double SetBytesFromProperty(object propertyValue, byte[] bytes, double numBytes, PropertyInfo propertyInfo) { int num = 0; int num2 = 0; byte[] array = null; switch (propertyValue.GetType().Name) { case "Boolean": num = (int)Math.Floor(numBytes); num2 = (int)((numBytes - (double)num) / 0.125); if ((bool)propertyValue) { bytes[num] |= (byte)Math.Pow(2.0, num2); } else { bytes[num] &= (byte)(~(byte)Math.Pow(2.0, num2)); } numBytes += 0.125; break; case "Byte": numBytes = (int)Math.Ceiling(numBytes); num = (int)numBytes; bytes[num] = (byte)propertyValue; numBytes += 1.0; break; case "Int16": array = Int.ToByteArray((short)propertyValue); break; case "UInt16": array = Word.ToByteArray((ushort)propertyValue); break; case "Int32": array = DInt.ToByteArray((int)propertyValue); break; case "UInt32": array = DWord.ToByteArray((uint)propertyValue); break; case "Single": array = Real.ToByteArray((float)propertyValue); break; case "Double": array = LReal.ToByteArray((double)propertyValue); break; case "String": //array = new byte[256]; //var res = GetGb2312()?.GetBytes(propertyValue?.ToString()); //for (int i = 0; i < res?.Length; i++) { array[i] = res[i]; } int len = 256; if (propertyInfo.CustomAttributes.Count() > 0) { var tempLen = propertyInfo.GetCustomAttribute(); if (tempLen != null) len = tempLen.Len + 2; } array = new byte[len]; var res = GetGb2312()?.GetBytes(propertyValue?.ToString()); if (array.Length > 2) array[0] = (byte)(len - 2); array[1] = (byte)res.Length; for (int i = 0; i < res?.Length; i++) { int index = i + 2; if (index < array.Length) array[index] = res[i]; } break; default: numBytes = ToBytes(propertyValue, bytes, numBytes); //if (propertyValue.GetType().IsClass) IncrementToEven(ref numBytes); break; } if (array != null) { IncrementToEven(ref numBytes); num = (int)numBytes; for (int i = 0; i < array.Length; i++) { bytes[num + i] = array[i]; } numBytes += (double)array.Length; } return numBytes; } public static double ToBytes(object sourceClass, byte[] bytes, double numBytes = 0.0) { foreach (PropertyInfo accessableProperty in GetAccessableProperties(sourceClass.GetType())) { if (accessableProperty.PropertyType.IsArray) { Array array = (Array)accessableProperty.GetValue(sourceClass, null); IncrementToEven(ref numBytes); accessableProperty.PropertyType.GetElementType(); for (int i = 0; i < array.Length; i++) { if (!(numBytes < (double)bytes.Length)) { break; } numBytes = SetBytesFromProperty(array.GetValue(i), bytes, numBytes, accessableProperty); } } else { numBytes = SetBytesFromProperty(accessableProperty.GetValue(sourceClass, null), bytes, numBytes, accessableProperty); } } return numBytes; } private static void IncrementToEven(ref double numBytes) { numBytes = Math.Ceiling(numBytes); if (numBytes % 2.0 > 0.0) { numBytes += 1.0; } } } }