public static void ReadFromReader(this ICommand command, BigEndianReader read) { var properties = command.GetType().GetProperties() .Where(f => f.GetCustomAttribute <CommandFieldAttribute>() != null) .Select(f => new { Property = f, Metadata = f.GetCustomAttribute <CommandFieldAttribute>() }); while (true) { byte fieldID = read.ReadByte(); if (fieldID == 255 || read.PeekChar() < 0) { break; } ushort fieldLength = read.ReadUInt16(); var fieldInfo = properties.First(f => f.Metadata.FieldID == fieldID); var serializationType = fieldInfo.Property.PropertyType; if (fieldInfo.Metadata.SerializeAs != null) { serializationType = fieldInfo.Metadata.SerializeAs; } if (Nullable.GetUnderlyingType(serializationType) != null) { serializationType = Nullable.GetUnderlyingType(serializationType); } if (fieldInfo.Metadata.Repeated) { if (!serializationType.GetInterfaces().Any(i => i == typeof(IList))) { throw new Exception("Repeated field is not of a list type"); } var listType = serializationType.GetInterfaces().First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList <>)); var internalSerializationType = listType.GetGenericArguments()[0]; var cur = fieldInfo.Property.GetValue(command) as IList; if (!serializationType.IsArray) { if (cur == null) { cur = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(internalSerializationType)); } cur.Add(read.ReadOfType(fieldLength, internalSerializationType)); } else { if (cur == null) { cur = Array.CreateInstance(internalSerializationType, 1); } else { var arr = Array.CreateInstance(internalSerializationType, cur.Count + 1); Array.Copy((Array)cur, arr, cur.Count); cur = arr; } cur[cur.Count - 1] = read.ReadOfType(fieldLength, internalSerializationType); } fieldInfo.Property.SetValue(command, cur); } else { var value = read.ReadOfType(fieldLength, serializationType); if (serializationType != fieldInfo.Property.PropertyType) { if (!fieldInfo.Property.PropertyType.IsEnum) { value = Convert.ChangeType(value, fieldInfo.Property.PropertyType); } } fieldInfo.Property.SetValue(command, value); } } }