public TOutput VisitProperties(TInput node, Func <TInput, TOutput> visit) { if (node == null) { return(default(TOutput)); } Type type = node.GetType(); PropertyInfo[] properties = ReflectionCache.GetReadWriteClassProperties(type); TOutput result = Clone ? (TOutput)Activator.CreateInstance(type) : default(TOutput); foreach (PropertyInfo prop in properties) { Type propType = prop.PropertyType; if (IgnoredProperties.Contains(prop.Name)) { continue; } else if (propType.IsValueType || propType == typeof(string) || propType == typeof(Regex)) { if (Clone) { prop.SetValue(result, prop.GetValue(node)); } } else if (typeof(TInput).IsAssignableFrom(propType)) { TOutput setValue = visit((TInput)prop.GetValue(node)); if (Clone) { prop.SetValue(result, setValue); } } else if (propType.GetInterfaces().Contains(typeof(IEnumerable))) { Type itemType = propType.GetGenericArguments()[0]; IList destCollection = null; var collection = prop.GetValue(node); if (collection != null) { IEnumerable <object> sourceCollection; if (collection is IEnumerable <object> refCollection) { sourceCollection = refCollection; } else { sourceCollection = ((IEnumerable)collection).Cast <object>(); } destCollection = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(itemType)); foreach (object item in sourceCollection) { object destItem = item is TInput sourceItem ? visit(sourceItem) : item; if (Clone) { destCollection.Add(destItem); } } } if (Clone) { prop.SetValue(result, destCollection); } } else { throw new NotImplementedException($"Property \"{prop}\" processing is not implemented via reflection"); } } return(result); }
public int Compare(object node, object other) { if (node == null && other == null) { return(0); } else if (node != null && other == null) { return(1); } else if (node == null && other != null) { return(-1); } Type type1 = node.GetType(); Type type2 = other.GetType(); if (!(type1.GetInterfaces().Contains(typeof(IList)) && type2.GetInterfaces().Contains(typeof(IList)))) { if (type1 != type2) { return(type1.Name.CompareTo(type2.Name)); } } int result = 0; var type1Interfaces = type1.GetInterfaces(); if (type1Interfaces.Contains(typeof(IComparable))) { var comparable1 = (IComparable)node; var comparable2 = (IComparable)other; result = comparable1.CompareTo(comparable2); if (result != 0) { return(result); } } else if (type1 == typeof(Regex)) { var comparable1 = (Regex)node; var comparable2 = (Regex)other; result = comparable1.ToString().CompareTo(comparable2.ToString()); if (result != 0) { return(result); } } else if (type1.IsSubclassOf(typeof(T)) || type1 == typeof(T)) { PropertyInfo[] properties1 = ReflectionCache.GetReadWriteClassProperties(type1); PropertyInfo[] properties2 = ReflectionCache.GetReadWriteClassProperties(type2); if (properties1.Length != properties2.Length) { return(properties1.Length - properties2.Length); } for (int i = 0; i < properties1.Length; i++) { if (!IgnoredProperties.Contains(properties1[i].Name)) { result = Compare(properties1[i].GetValue(node), properties2[i].GetValue(other)); if (result != 0) { return(result); } } } } else if (type1Interfaces.Contains(typeof(IList))) { var node1List = (IList)node; var node2List = (IList)other; if (node1List.Count != node2List.Count) { return(node1List.Count - node2List.Count); } for (int i = 0; i < node1List.Count; i++) { result = Compare(node1List[i], node2List[i]); if (result != 0) { return(result); } } } else { throw new NotImplementedException($"Type \"{type1}\" comparison is not implemented via reflection"); } return(0); }