/// <summary> /// Method to assign the value of one type to another /// </summary> /// <param name="from">Other object</param> public void Assign(ModelObject from) { // Assigning null values is not supported if (from == null) { throw new ArgumentNullException(nameof(from)); } // Validate the types Type myType = GetType(); if (from.GetType() != myType) { throw new ArgumentException("Types do not match", nameof(from)); } // Assign property values foreach (PropertyInfo property in GetType().GetProperties()) { if (property.PropertyType.IsSubclassOf(typeof(ModelObject))) { ModelObject oldValue = (ModelObject)property.GetValue(this); ModelObject newValue = (ModelObject)property.GetValue(from); if (oldValue == null || newValue == null) { property.SetValue(this, newValue); } else if (oldValue.GetType() != newValue.GetType()) { property.SetValue(this, newValue.Clone()); } else { oldValue.Assign(newValue); } } else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType)) { IList oldModelCollection = (IList)property.GetValue(this); IList newModelCollection = (IList)property.GetValue(from); if (ModelGrowingCollection.TypeMatches(property.PropertyType)) { ModelGrowingCollectionHelper.Assign(oldModelCollection, newModelCollection); } else { ModelCollectionHelper.Assign(oldModelCollection, itemType, newModelCollection); } } else { object newValue = property.GetValue(from); property.SetValue(this, newValue); } } }
/// <summary> /// Create a clone of this instance /// </summary> /// <returns>Cloned object</returns> public object Clone() { // Make a new clone Type myType = GetType(); ModelObject clone = (ModelObject)Activator.CreateInstance(myType); // Assign cloned property values foreach (PropertyInfo property in GetType().GetProperties()) { if (property.PropertyType.IsSubclassOf(typeof(ModelObject))) { ModelObject value = (ModelObject)property.GetValue(this); ModelObject cloneValue = (ModelObject)property.GetValue(clone); if (value == null || cloneValue == null) { property.SetValue(clone, value); } else if (value.GetType() != cloneValue.GetType()) { property.SetValue(clone, value.Clone()); } else { cloneValue.Assign(value); } } else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType)) { IList collection = (IList)property.GetValue(this); IList clonedCollection = (IList)property.GetValue(clone); if (ModelGrowingCollection.TypeMatches(property.PropertyType)) { ModelGrowingCollectionHelper.Assign(clonedCollection, collection); } else { ModelCollectionHelper.Assign(clonedCollection, itemType, collection); } } else if (property.PropertyType.IsAssignableFrom(typeof(ICloneable))) { ICloneable value = (ICloneable)property.GetValue(this); property.SetValue(clone, value?.Clone()); } else { object value = property.GetValue(this); property.SetValue(clone, value); } } return(clone); }
/// <summary> /// Update a specific key of this instance from a given JSON element as provided by the firmware /// </summary> /// <param name="key">Property name to update</param> /// <param name="jsonElement">Element to update this intance from</param> /// <returns>Whether the key could be updated</returns> public bool UpdateFromFirmwareModel(string key, JsonElement jsonElement) { if (string.IsNullOrEmpty(key)) { UpdateFromJson(jsonElement, true); return(true); } if (JsonProperties.TryGetValue(key, out PropertyInfo property)) { if (Attribute.IsDefined(property, typeof(LinuxPropertyAttribute))) { // Skip this field if it must not be updated from RRF return(true); } if (property.PropertyType.IsSubclassOf(typeof(ModelObject))) { ModelObject value = (ModelObject)property.GetValue(this); value.UpdateFromJson(jsonElement, true); return(true); } if (ModelCollection.GetItemType(property.PropertyType, out Type itemType)) { IList modelCollection = (IList)property.GetValue(this); if (ModelGrowingCollection.TypeMatches(property.PropertyType)) { ModelGrowingCollectionHelper.UpdateFromJson(modelCollection, itemType, jsonElement, true); } else { ModelCollectionHelper.UpdateFromJson(modelCollection, itemType, jsonElement, true); } return(true); } #if VERIFY_OBJECT_MODEL Console.WriteLine("[warn] Missing key type handler for {0}", key); } else { Console.WriteLine("[warn] Missing property: {0} = {1}", key, jsonElement.GetRawText()); #endif } // Failed to find a property return(false); }
/// <summary> /// Update this instance from a given JSON element /// </summary> /// <param name="jsonElement">Element to update this intance from</param> /// <param name="ignoreSbcProperties">Whether SBC properties are ignored</param> /// <returns>Updated instance</returns> /// <exception cref="JsonException">Failed to deserialize data</exception> internal virtual ModelObject UpdateFromJson(JsonElement jsonElement, bool ignoreSbcProperties) { foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject()) { if (JsonProperties.TryGetValue(jsonProperty.Name, out PropertyInfo property)) { if (ignoreSbcProperties && Attribute.IsDefined(property, typeof(LinuxPropertyAttribute))) { // Skip this field if it must not be updated continue; } if (property.PropertyType.IsSubclassOf(typeof(ModelObject))) { ModelObject modelObject = (ModelObject)property.GetValue(this); if (jsonProperty.Value.ValueKind == JsonValueKind.Null) { if (modelObject != null) { if (property.SetMethod != null) { property.SetValue(this, null); } #if VERIFY_OBJECT_MODEL else { Console.WriteLine("[warn] Tried to set unsettable property {0} to null", jsonProperty.Name); } #endif } } else if (modelObject == null) { modelObject = (ModelObject)Activator.CreateInstance(property.PropertyType); modelObject = modelObject.UpdateFromJson(jsonProperty.Value, ignoreSbcProperties); if (property.SetMethod != null) { property.SetValue(this, modelObject); } #if VERIFY_OBJECT_MODEL else { Console.WriteLine("[warn] Tried to assign unsettable property {0} = {1}", jsonProperty.Name, jsonProperty.Value.GetRawText()); } #endif } else { ModelObject updatedInstance = modelObject.UpdateFromJson(jsonProperty.Value, ignoreSbcProperties); if (updatedInstance != modelObject) { if (property.SetMethod != null) { property.SetValue(this, updatedInstance); } #if VERIFY_OBJECT_MODEL else { Console.WriteLine("[warn] Tried to assign unsettable property {0} = {1}", jsonProperty.Name, jsonProperty.Value.GetRawText()); } #endif } } } else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType)) { IList modelCollection = (IList)property.GetValue(this); if (ModelGrowingCollection.TypeMatches(property.PropertyType)) { ModelGrowingCollectionHelper.UpdateFromJson(modelCollection, itemType, jsonProperty.Value, ignoreSbcProperties); } else { ModelCollectionHelper.UpdateFromJson(modelCollection, itemType, jsonProperty.Value, ignoreSbcProperties); } } else if (property.PropertyType == typeof(bool) && jsonProperty.Value.ValueKind == JsonValueKind.Number) { try { if (property.SetMethod != null) { property.SetValue(this, Convert.ToBoolean(jsonProperty.Value.GetInt32())); #if VERIFY_OBJECT_MODEL Console.WriteLine("[warn] Updating bool value from number {0} = {1}", jsonProperty.Name, jsonProperty.Value.GetRawText()); #endif } #if VERIFY_OBJECT_MODEL else { Console.WriteLine("[warn] Tried to assign unsettable property {0} = {1}", jsonProperty.Name, jsonProperty.Value.GetRawText()); } #endif } catch (FormatException e) { throw new JsonException($"Failed to deserialize property [{GetType().Name}].{property.Name} (type bool) from JSON {jsonProperty.Value.GetRawText()}", e); } } else { try { object newValue = JsonSerializer.Deserialize(jsonProperty.Value.GetRawText(), property.PropertyType); if (property.SetMethod != null) { property.SetValue(this, newValue); } #if VERIFY_OBJECT_MODEL else { Console.WriteLine("[warn] Tried to assign unsettable property {0} = {1}", jsonProperty.Name, jsonProperty.Value.GetRawText()); } #endif } catch (JsonException e) { throw new JsonException($"Failed to deserialize property [{GetType().Name}].{property.Name} (type {property.PropertyType.Name}) from JSON {jsonProperty.Value.GetRawText()}", e); } } } #if VERIFY_OBJECT_MODEL else if (jsonProperty.Name != "seqs") { Console.WriteLine("[warn] Missing property: {0} = {1}", jsonProperty.Name, jsonProperty.Value.GetRawText()); } #endif } return(this); }