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);
            }
        }