public static bool IsSpecified(this MergableElement obj, string propertyName) { PropertyInfo property = obj.GetType().GetProperty($"{propertyName}Specified"); if (property != null && property.PropertyType == typeof(bool)) { return((bool)property.GetValue(obj)); } return(true); }
public void Merge(MergableElement baseElement) { foreach (PropertyInfo property in GetType().GetProperties()) { if (Unmergables.Contains(property.Name)) { continue; } if (property.PropertyType.IsArray) { Array values = (Array)property.GetValue(this); Array baseValues = (Array)property.GetValue(baseElement); if (values == null) { property.SetValue(this, baseValues); continue; } if (baseValues == null) { continue; } bool mergable = typeof(MergableElement).IsAssignableFrom(values.GetType().GetElementType()); IList result = MakeList(values.GetType().GetElementType()); foreach (object value in values) { if (mergable) { MergableElement baseValue = baseValues.OfType <MergableElement>().FirstOrDefault(m => m.Equals(value)); if (baseValue != null) { ((MergableElement)value).Merge(baseValue); } } result.Add(value); } foreach (object additional in baseValues.Cast <object>().Except(values.Cast <object>())) { result.Add(additional); } property.SetValue(this, result.GetType().GetMethod("ToArray")?.Invoke(result, Array.Empty <object>())); } else { object value = property.GetValue(this); object baseValue = property.GetValue(baseElement); property.SetValue(this, MergeValues(value, baseValue, this.IsSpecified(property.Name))); } } IList MakeList(System.Type type) { System.Type listType = typeof(List <>); System.Type constructedListType = listType.MakeGenericType(type); return((IList)Activator.CreateInstance(constructedListType)); } object MergeValues(object value, object baseValue, bool specified) { if (value is MergableElement mergableElement && baseValue is MergableElement baseMergableElement) { mergableElement.Merge(baseMergableElement); return(mergableElement); } return(!specified ? baseValue : value); } }