我死去
目前添加了一个能够深度查找和设置反射的helper,但是Tag的系统仍然不完全,另外我觉得console可以重构了 Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
325
Assets/Scripts/Extensions/ReflectionHelper.cs
Normal file
325
Assets/Scripts/Extensions/ReflectionHelper.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
public static class ReflectionHelper
|
||||
{
|
||||
private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
// --- 设置值 (支持 object) ---
|
||||
public static void SetDeepValue(object target, string path, object newValue)
|
||||
{
|
||||
if (target == null || string.IsNullOrEmpty(path)) return;
|
||||
string[] parts = path.Split('.');
|
||||
SetDeepValueRecursive(target, parts, 0, newValue);
|
||||
}
|
||||
|
||||
private static void SetDeepValueRecursive(object currentObj, string[] pathParts, int index, object newValue)
|
||||
{
|
||||
string memberName = pathParts[index];
|
||||
Type type = currentObj.GetType();
|
||||
|
||||
FieldInfo field = type.GetField(memberName, Flags);
|
||||
PropertyInfo prop = type.GetProperty(memberName, Flags);
|
||||
|
||||
if (field == null && prop == null)
|
||||
{
|
||||
// Debug.LogWarning($"找不到成员: {memberName}"); // 可选:调试用
|
||||
return;
|
||||
}
|
||||
|
||||
bool isLast = index == pathParts.Length - 1;
|
||||
|
||||
if (isLast)
|
||||
{
|
||||
// 到达终点:直接设置值
|
||||
// 注意:这里可能需要处理类型转换,取决于你的 newValue 类型是否严格匹配
|
||||
try
|
||||
{
|
||||
if (field != null) field.SetValue(currentObj, newValue);
|
||||
else if (prop != null && prop.CanWrite) prop.SetValue(currentObj, newValue);
|
||||
}
|
||||
catch (Exception e) { Debug.LogError($"设置值失败 {memberName}: {e.Message}"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
// 中间节点
|
||||
object nextObj = field != null ? field.GetValue(currentObj) : prop.GetValue(currentObj);
|
||||
if (nextObj == null) return;
|
||||
|
||||
SetDeepValueRecursive(nextObj, pathParts, index + 1, newValue);
|
||||
|
||||
// Struct 回写逻辑 (关键)
|
||||
if (nextObj.GetType().IsValueType)
|
||||
{
|
||||
if (field != null) field.SetValue(currentObj, nextObj);
|
||||
else if (prop != null && prop.CanWrite) prop.SetValue(currentObj, nextObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 获取值 (支持 object) ---
|
||||
public static object GetDeepValue(object target, string path)
|
||||
{
|
||||
object current = target;
|
||||
foreach (string part in path.Split('.'))
|
||||
{
|
||||
if (current == null) return null;
|
||||
Type type = current.GetType();
|
||||
|
||||
FieldInfo field = type.GetField(part, Flags);
|
||||
if (field != null)
|
||||
{
|
||||
current = field.GetValue(current);
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyInfo prop = type.GetProperty(part, Flags);
|
||||
if (prop != null)
|
||||
{
|
||||
current = prop.GetValue(current);
|
||||
continue;
|
||||
}
|
||||
return null; // 路径中断
|
||||
}
|
||||
return current;
|
||||
}
|
||||
/// <summary>
|
||||
/// 遍历对象的所有字段和属性(递归地),查找值与目标值匹配的参数路径。
|
||||
/// </summary>
|
||||
/// <param name="target">要搜索的对象实例。</param>
|
||||
/// <param name="targetValue">要匹配的目标值。</param>
|
||||
/// <param name="maxDepth">递归搜索的最大深度,防止无限循环。</param>
|
||||
/// <returns>返回匹配参数的完整路径列表 (例如: "position.x")。</returns>
|
||||
public static List<string> FindParametersByValue(object target, object targetValue, int maxDepth = 10)
|
||||
{
|
||||
if (target == null || targetValue == null) return new List<string>();
|
||||
|
||||
// 用于存储找到的路径
|
||||
var results = new List<string>();
|
||||
|
||||
// 用于防止循环引用(比如类 A 内部引用了类 B,类 B 内部又引用了类 A)
|
||||
var visited = new HashSet<object>();
|
||||
|
||||
// 启动递归搜索
|
||||
FindRecursive(target, targetValue, "", 0, results, visited, maxDepth);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void FindRecursive(
|
||||
object currentObject,
|
||||
object targetValue,
|
||||
string currentPath,
|
||||
int depth,
|
||||
List<string> results,
|
||||
HashSet<object> visited,
|
||||
int maxDepth)
|
||||
{
|
||||
if (currentObject == null || depth >= maxDepth) return;
|
||||
|
||||
// 避免无限循环和重复搜索
|
||||
// 对于值类型 (Struct) 不需要加入 visited,因为它们是副本
|
||||
if (!currentObject.GetType().IsValueType)
|
||||
{
|
||||
// 如果对象已经被搜索过,则跳过
|
||||
if (visited.Contains(currentObject)) return;
|
||||
visited.Add(currentObject);
|
||||
}
|
||||
|
||||
Type currentType = currentObject.GetType();
|
||||
|
||||
// 1. 遍历 Field 字段
|
||||
foreach (var field in currentType.GetFields(Flags))
|
||||
{
|
||||
// 跳过内部字段,如编译器生成的 backing fields
|
||||
if (field.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false)) continue;
|
||||
|
||||
object value = field.GetValue(currentObject);
|
||||
string newPath = string.IsNullOrEmpty(currentPath) ? field.Name : $"{currentPath}.{field.Name}";
|
||||
|
||||
CheckAndRecurse(field.FieldType, value, targetValue, newPath, depth, results, visited, maxDepth);
|
||||
}
|
||||
|
||||
// 2. 遍历 Property 属性
|
||||
foreach (var prop in currentType.GetProperties(Flags).Where(p => p.CanRead))
|
||||
{
|
||||
// 跳过索引器
|
||||
if (prop.GetIndexParameters().Length > 0) continue;
|
||||
|
||||
object value = prop.GetValue(currentObject);
|
||||
string newPath = string.IsNullOrEmpty(currentPath) ? prop.Name : $"{currentPath}.{prop.Name}";
|
||||
|
||||
CheckAndRecurse(prop.PropertyType, value, targetValue, newPath, depth, results, visited, maxDepth);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查当前值是否匹配,如果不是基础类型则继续递归
|
||||
/// </summary>
|
||||
private static void CheckAndRecurse(
|
||||
Type valueType,
|
||||
object value,
|
||||
object targetValue,
|
||||
string newPath,
|
||||
int depth,
|
||||
List<string> results,
|
||||
HashSet<object> visited,
|
||||
int maxDepth)
|
||||
{
|
||||
if (value == null) return;
|
||||
|
||||
// 【值匹配检查】
|
||||
if (value.Equals(targetValue))
|
||||
{
|
||||
results.Add(newPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// 【递归检查】
|
||||
// 只有当值是一个复杂类型(Class 或 Struct)时才需要递归
|
||||
// 排除字符串和集合(List, Array等,如果你需要搜索集合内部,逻辑会更复杂)
|
||||
if (valueType.IsClass || valueType.IsValueType && !valueType.IsPrimitive)
|
||||
{
|
||||
// 排除 String (虽然是 Class,但我们视其为基础值)
|
||||
if (valueType == typeof(string)) return;
|
||||
|
||||
// 排除集合(如果需要支持 List<T> 的内部搜索,你需要在这里添加处理逻辑)
|
||||
if (valueType.IsArray || valueType.IsGenericType && valueType.GetInterfaces().Any(i => i == typeof(System.Collections.IEnumerable))) return;
|
||||
|
||||
// 递归进入下一层
|
||||
FindRecursive(value, targetValue, newPath, depth + 1, results, visited, maxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class FastReflection
|
||||
{
|
||||
// 定义一个节点,用来缓存每一层的 Field 或 Property 信息
|
||||
private class MemberNode
|
||||
{
|
||||
public FieldInfo Field;
|
||||
public PropertyInfo Property;
|
||||
public bool IsField => Field != null;
|
||||
|
||||
public MemberNode(MemberInfo info)
|
||||
{
|
||||
if (info is FieldInfo f) Field = f;
|
||||
else if (info is PropertyInfo p) Property = p;
|
||||
}
|
||||
|
||||
// 快速获取值
|
||||
public object GetValue(object target)
|
||||
{
|
||||
return IsField ? Field.GetValue(target) : Property.GetValue(target);
|
||||
}
|
||||
|
||||
// 快速设置值
|
||||
public void SetValue(object target, object value)
|
||||
{
|
||||
if (IsField) Field.SetValue(target, value);
|
||||
else if (Property != null && Property.CanWrite) Property.SetValue(target, value);
|
||||
}
|
||||
|
||||
// 判断这一层是否是 Struct (值类型),如果是,修改后需要回写
|
||||
public bool IsStructType()
|
||||
{
|
||||
return IsField ? Field.FieldType.IsValueType : Property.PropertyType.IsValueType;
|
||||
}
|
||||
}
|
||||
|
||||
// 访问器链条
|
||||
private readonly List<MemberNode> _nodes = new List<MemberNode>();
|
||||
private bool _isValid = false;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数:初始化时进行昂贵的解析操作(只做一次)
|
||||
/// </summary>
|
||||
public FastReflection(object rootTarget, string path)
|
||||
{
|
||||
if (rootTarget == null || string.IsNullOrEmpty(path)) return;
|
||||
|
||||
Type currentType = rootTarget.GetType();
|
||||
string[] parts = path.Split('.');
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
// 查找字段或属性
|
||||
FieldInfo field = currentType.GetField(part, flags);
|
||||
PropertyInfo prop = currentType.GetProperty(part, flags);
|
||||
|
||||
if (field == null && prop == null)
|
||||
{
|
||||
Debug.LogError($"[FastReflection] 路径中断: 找不到成员 '{part}' 在类型 '{currentType.Name}' 中");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建节点并添加到链条
|
||||
MemberNode node = new MemberNode(field ?? (MemberInfo)prop);
|
||||
_nodes.Add(node);
|
||||
|
||||
// 更新 currentType 为下一层的类型
|
||||
currentType = field != null ? field.FieldType : prop.PropertyType;
|
||||
}
|
||||
|
||||
_isValid = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取值(运行时极快)
|
||||
/// </summary>
|
||||
public float GetValue(object rootTarget)
|
||||
{
|
||||
if (!_isValid) return 0f;
|
||||
|
||||
object current = rootTarget;
|
||||
for (int i = 0; i < _nodes.Count; i++)
|
||||
{
|
||||
current = _nodes[i].GetValue(current);
|
||||
if (current == null) return 0f;
|
||||
}
|
||||
|
||||
return (float)current; // 假设最后一定是 float
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置值(运行时极快,自动处理 Struct 回写)
|
||||
/// </summary>
|
||||
public void SetValue(object rootTarget, float newValue)
|
||||
{
|
||||
if (!_isValid) return;
|
||||
|
||||
// 开始递归处理回写
|
||||
SetRecursive(rootTarget, 0, newValue);
|
||||
}
|
||||
|
||||
// 递归函数:处理“获取-修改-回写”逻辑
|
||||
private void SetRecursive(object currentObj, int index, float finalValue)
|
||||
{
|
||||
MemberNode node = _nodes[index];
|
||||
|
||||
// 1. 如果是链条的最后一个节点(即那个 float 变量)
|
||||
if (index == _nodes.Count - 1)
|
||||
{
|
||||
node.SetValue(currentObj, finalValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 如果是中间节点,先获取下一层对象
|
||||
object nextObj = node.GetValue(currentObj);
|
||||
if (nextObj == null) return;
|
||||
|
||||
// 3. 递归进入下一层
|
||||
SetRecursive(nextObj, index + 1, finalValue);
|
||||
|
||||
// 4. 【关键】回写阶段
|
||||
// 如果 nextObj 是 Struct(值类型),比如 Vector3,
|
||||
// 我们刚才在递归里修改了 nextObj 的副本,现在必须把它赋值回 currentObj
|
||||
if (node.IsStructType())
|
||||
{
|
||||
node.SetValue(currentObj, nextObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Extensions/ReflectionHelper.cs.meta
Normal file
11
Assets/Scripts/Extensions/ReflectionHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8465d62ddf65c945924e35a0c1851ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user