/// <summary>
        /// Recursively scan the MonoBehaviours of a GameObject and its children.
        /// For each field found, look up its value in the internal dictionary.
        /// If it's present and its value in the dictionary differs from the actual
        /// value in the game object, Set the GameObject's value using the value
        /// recorded in the dictionary.
        /// </summary>
        public bool PutFieldValues(GameObject go, GameObject[] roots)
        {
            GameObjectFieldScanner scanner = new GameObjectFieldScanner();

            scanner.FilterField = FilterField;
            scanner.OnLeafField = (string fullName, Type type, ref object value) =>
            {
                // Lookup the value in the dictionary
                string savedValue;
                if (mValues.TryGetValue(fullName, out savedValue) &&
                    StringFromLeafObject(value) != savedValue)
                {
                    //Debug.Log("Put " + mObjectFullPath + "." + fullName + " = " + mValues[fullName]);
                    value = LeafObjectFromString(type, mValues[fullName].Trim(), roots);
                    return(true);    // changed
                }
                return(false);
            };
            scanner.OnFieldValueChanged = (fullName, fieldInfo, fieldOwner, value) =>
            {
                fieldInfo.SetValue(fieldOwner, value);
                return(true);
            };
            return(scanner.ScanFields(go));
        }
        /// <summary>
        /// Recursively scan the MonoBehaviours of a GameObject and its children.
        /// For each field found, look up its value in the internal dictionary.
        /// If it's present and its value in the dictionary differs from the actual
        /// value in the game object, Set the GameObject's value using the value
        /// recorded in the dictionary.
        /// </summary>
        public bool PutFieldValues(GameObject go, GameObject[] roots)
        {
            GameObjectFieldScanner scanner = new GameObjectFieldScanner();

            scanner.FilterField     = FilterField;
            scanner.FilterComponent = HasSaveDuringPlay;
            scanner.OnLeafField     = (string fullName, Type type, ref object value) =>
            {
                // Lookup the value in the dictionary
                if (mValues.TryGetValue(fullName, out string savedValue) &&
                    StringFromLeafObject(value) != savedValue)
                {
                    //Debug.Log("Put " + mObjectFullPath + "." + fullName + " = " + mValues[fullName]);
                    value = LeafObjectFromString(type, mValues[fullName].Trim(), roots);
                    return(true);    // changed
                }
                return(false);
            };
            scanner.OnFieldValueChanged = (fullName, fieldInfo, fieldOwner, value) =>
            {
                fieldInfo.SetValue(fieldOwner, value);
                if (PrefabUtility.GetPrefabInstanceStatus(go) != PrefabInstanceStatus.NotAPrefab)
                {
                    PrefabUtility.RecordPrefabInstancePropertyModifications(scanner.LeafObject);
                }
                return(true);
            };
            return(scanner.ScanFields(go));
        }
        /// <summary>
        /// Recursively collect all the field values in the MonoBehaviours
        /// owned by this object and its descendants.  The values are stored
        /// in an internal dictionary.
        /// </summary>
        public void CollectFieldValues(GameObject go)
        {
            mObjectFullPath = ObjectTreeUtil.GetFullName(go);
            GameObjectFieldScanner scanner = new GameObjectFieldScanner();

            scanner.FilterField = FilterField;
            scanner.OnLeafField = (string fullName, Type type, ref object value) =>
            {
                // Save the value in the dictionary
                mValues[fullName] = StringFromLeafObject(value);
                //Debug.Log(mObjectFullPath + "." + fullName + " = " + mValues[fullName]);
                return(false);
            };
            scanner.ScanFields(go);
        }