#nullable enable using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; namespace Terminal.Gui; /// /// Holds a property's value and the that allows to /// get and set the property's value. /// /// /// Configuration properties must be and and have the /// attribute. If the type of the property requires specialized JSON /// serialization, a must be provided using the /// attribute. /// public class ConfigProperty { /// Describes the property. public PropertyInfo? PropertyInfo { get; set; } /// /// Holds the property's value as it was either read from the class's implementation or from a config file. If the /// property has not been set (e.g. because no configuration file specified a value), this will be /// . /// /// /// On , performs a sparse-copy of the new value to the existing value (only copies elements /// of the object that are non-null). /// public object? PropertyValue { get; set; } /// Applies the to the property described by . /// public bool Apply () { if (PropertyValue is { }) { try { if (PropertyInfo?.GetValue (null) is { }) { PropertyInfo?.SetValue (null, DeepMemberWiseCopy (PropertyValue, PropertyInfo?.GetValue (null))); } } catch (TargetInvocationException tie) { // Check if there is an inner exception if (tie.InnerException is { }) { // Handle the inner exception separately without catching the outer exception Exception? innerException = tie.InnerException; // Handle the inner exception here throw new JsonException ( $"Error Applying Configuration Change: {innerException.Message}", innerException ); } // Handle the outer exception or rethrow it if needed throw new JsonException ($"Error Applying Configuration Change: {tie.Message}", tie); } catch (ArgumentException ae) { throw new JsonException ( $"Error Applying Configuration Change ({PropertyInfo?.Name}): {ae.Message}", ae ); } } return PropertyValue != null; } /// /// Helper to get either the Json property named (specified by [JsonPropertyName(name)] or the actual property /// name. /// /// /// public static string GetJsonPropertyName (PropertyInfo pi) { var attr = pi.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; return attr?.Name ?? pi.Name; } /// /// Retrieves (using reflection) the value of the static property described in into /// . /// /// public object? RetrieveValue () { return PropertyValue = PropertyInfo!.GetValue (null); } internal object? UpdateValueFrom (object source) { if (source is null) { return PropertyValue; } Type? ut = Nullable.GetUnderlyingType (PropertyInfo!.PropertyType); if (source.GetType () != PropertyInfo!.PropertyType && ut is { } && source.GetType () != ut) { throw new ArgumentException ( $"The source object ({ PropertyInfo!.DeclaringType }.{ PropertyInfo!.Name }) is not of type { PropertyInfo!.PropertyType }." ); } if (PropertyValue is { }) { PropertyValue = DeepMemberWiseCopy (source, PropertyValue); } else { PropertyValue = source; } return PropertyValue; } }