using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Unity.VisualScripting { public abstract class ReflectedCloner : Cloner { public override bool Handles(Type type) { return false; // Should only be used as a fallback cloner } public override void FillClone(Type type, ref object clone, object original, CloningContext context) { if (PlatformUtility.supportsJit) { foreach (var accessor in GetOptimizedAccessors(type)) { if (context.tryPreserveInstances) { var cloneProperty = accessor.GetValue(clone); Cloning.CloneInto(context, ref cloneProperty, accessor.GetValue(original)); accessor.SetValue(clone, cloneProperty); } else { accessor.SetValue(clone, Cloning.Clone(context, accessor.GetValue(original))); } } } else { foreach (var accessor in GetAccessors(type)) { if (accessor is FieldInfo) { var field = (FieldInfo)accessor; if (context.tryPreserveInstances) { var cloneProperty = field.GetValue(clone); Cloning.CloneInto(context, ref cloneProperty, field.GetValue(original)); field.SetValue(clone, cloneProperty); } else { field.SetValue(clone, Cloning.Clone(context, field.GetValue(original))); } } else if (accessor is PropertyInfo) { var property = (PropertyInfo)accessor; if (context.tryPreserveInstances) { var cloneProperty = property.GetValue(clone, null); Cloning.CloneInto(context, ref cloneProperty, property.GetValue(original, null)); property.SetValue(clone, cloneProperty, null); } else { property.SetValue(clone, Cloning.Clone(context, property.GetValue(original, null)), null); } } } } } private readonly Dictionary accessors = new Dictionary(); private MemberInfo[] GetAccessors(Type type) { if (!accessors.ContainsKey(type)) { accessors.Add(type, GetMembers(type).ToArray()); } return accessors[type]; } private readonly Dictionary optimizedAccessors = new Dictionary(); private IOptimizedAccessor[] GetOptimizedAccessors(Type type) { if (!optimizedAccessors.ContainsKey(type)) { var list = new List(); foreach (var member in GetMembers(type)) { if (member is FieldInfo) { list.Add(((FieldInfo)member).Prewarm()); } else if (member is PropertyInfo) { list.Add(((PropertyInfo)member).Prewarm()); } } optimizedAccessors.Add(type, list.ToArray()); } return optimizedAccessors[type]; } protected virtual IEnumerable GetMembers(Type type) { var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; return LinqUtility.Concat ( type.GetFields(bindingFlags).Where(IncludeField), type.GetProperties(bindingFlags).Where(IncludeProperty) ); } protected virtual bool IncludeField(FieldInfo field) { return false; } protected virtual bool IncludeProperty(PropertyInfo property) { return false; } } }