private void SerializeClass(T signal, string selectorString, object obj)
        {
            // Convenience function for setting multiple contexts at once
            var contexts = new List <IDisposable>
            {
                LogContext.PushProperty("SelectorString", selectorString),
                LogContext.PushProperty("Object", obj.GetType().Name)
            };
            Type t = obj.GetType();

            var members = t.GetPropertiesAndFields(MemberAccessibility.Readable)
                          .Where(m => m.IsDefined <RFmxSerializableAttribute>());

            foreach (MemberInfo member in members)
            {
                using (LogContext.PushProperty("MemberName", member.Name))
                {
                    object value = member.GetValue(obj);
                    RFmxSerializableAttribute attr = member.GetCustomAttribute <RFmxSerializableAttribute>();
                    try
                    {
                        SerializeValue(signal, selectorString, value, attr);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Error applying member");
                    }
                }
            }
            // Dispose both set contexts
            foreach (IDisposable context in contexts)
            {
                context.Dispose();
            }
        }
        private void SerializeValue(T signal, string selectorString, object obj, RFmxSerializableAttribute attr)
        {
            switch (obj)
            {
            case bool boolValue:
                ApplyConfiguration(signal, selectorString, boolValue, (RFmxSerializablePropertyAttribute)attr);
                break;

            case double doubleValue:
                ApplyConfiguration(signal, selectorString, doubleValue, (RFmxSerializablePropertyAttribute)attr);
                break;

            case int intValue:
                ApplyConfiguration(signal, selectorString, intValue, (RFmxSerializablePropertyAttribute)attr);
                break;

            case Enum enumValue:
                ApplyConfiguration(signal, selectorString, enumValue, (RFmxSerializablePropertyAttribute)attr);
                break;

            case string stringValue:
                ApplyConfiguration(signal, selectorString, stringValue, (RFmxSerializablePropertyAttribute)attr);
                break;

            case IList list:
                int i = 0;
                foreach (object o in list)
                {
                    string elementSelectorString;
                    if (attr is RFmxSerializableSectionAttribute sectionAttrList)
                    {
                        elementSelectorString = BuildSelectorString(selectorString, sectionAttrList.SelectorString, i);
                    }
                    else
                    {
                        elementSelectorString = selectorString;
                    }
                    SerializeValue(signal, elementSelectorString, o, null);
                    i++;
                }
                break;

            case null:
                break;

            default:
                if (attr is RFmxSerializableSectionAttribute sectionAttr)
                {
                    if (!string.IsNullOrEmpty(sectionAttr.SelectorString))
                    {
                        selectorString = BuildSelectorString(selectorString, sectionAttr.SelectorString, 0);
                    }
                }
                SerializeClass(signal, selectorString, obj);
                break;
            }
        }