435 lines
15 KiB
C#
435 lines
15 KiB
C#
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;
|
||
|
||
// --- 寻址缓存核心区 ---
|
||
private static readonly Dictionary<string, DeepAccessor> _accessors = new Dictionary<string, DeepAccessor>();
|
||
|
||
public static DeepAccessor GetAccessor(Type rootType, string path)
|
||
{
|
||
string key = $"{rootType.FullName}:{path}";
|
||
if (!_accessors.TryGetValue(key, out var accessor))
|
||
{
|
||
accessor = new DeepAccessor(rootType, path);
|
||
_accessors[key] = accessor;
|
||
}
|
||
return accessor;
|
||
}
|
||
|
||
// --- 【无感替换口】设置深层递归值 ---
|
||
public static void SetDeepValue(object target, string path, object newValue)
|
||
{
|
||
if (target == null || string.IsNullOrEmpty(path)) return;
|
||
GetAccessor(target.GetType(), path).SetValue(target, newValue);
|
||
}
|
||
|
||
// --- 【无感替换口】获取深层递归值 ---
|
||
public static object GetDeepValue(object target, string path)
|
||
{
|
||
if (target == null || string.IsNullOrEmpty(path)) return null;
|
||
return GetAccessor(target.GetType(), path).GetValue(target);
|
||
}
|
||
|
||
/// <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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找对象中第一个与目标值相等的字段/属性路径(可直接用于 SetDeepValue)。找不到则返回 null。
|
||
/// </summary>
|
||
public static string FindFirstParameterPathByValue(object target, object targetValue, int maxDepth = 10)
|
||
{
|
||
if (target == null || targetValue == null) return null;
|
||
var results = FindParametersByValue(target, targetValue, maxDepth);
|
||
return results.Count > 0 ? results[0] : null;
|
||
}
|
||
}
|
||
|
||
// --- 以下为全自动高速路由存取器 ---
|
||
public class DeepAccessor
|
||
{
|
||
private abstract class PathNode
|
||
{
|
||
public abstract object Get(object target);
|
||
public abstract void Set(object target, object value);
|
||
public abstract Type ReturnType { get; }
|
||
public abstract bool IsValueType { get; }
|
||
}
|
||
|
||
private class FieldNode : PathNode
|
||
{
|
||
private FieldInfo field;
|
||
public FieldNode(FieldInfo f) { field = f; }
|
||
public override object Get(object target) => field.GetValue(target);
|
||
public override void Set(object target, object value) => field.SetValue(target, value);
|
||
public override Type ReturnType => field.FieldType;
|
||
public override bool IsValueType => field.FieldType.IsValueType;
|
||
}
|
||
|
||
private class PropertyNode : PathNode
|
||
{
|
||
private PropertyInfo prop;
|
||
public PropertyNode(PropertyInfo p) { prop = p; }
|
||
public override object Get(object target) => prop.GetValue(target);
|
||
public override void Set(object target, object value) { if(prop.CanWrite) prop.SetValue(target, value); }
|
||
public override Type ReturnType => prop.PropertyType;
|
||
public override bool IsValueType => prop.PropertyType.IsValueType;
|
||
}
|
||
|
||
private class IndexNode : PathNode
|
||
{
|
||
private int index;
|
||
private Type returnType;
|
||
|
||
public IndexNode(int idx, Type colType)
|
||
{
|
||
index = idx;
|
||
if (colType.IsArray) returnType = colType.GetElementType();
|
||
else if (typeof(System.Collections.IList).IsAssignableFrom(colType))
|
||
{
|
||
var dictArgs = colType.GetGenericArguments();
|
||
returnType = dictArgs.Length > 0 ? dictArgs[0] : typeof(object);
|
||
}
|
||
}
|
||
|
||
public override object Get(object target)
|
||
{
|
||
if (target is System.Collections.IList list && index >= 0 && index < list.Count) return list[index];
|
||
if (target is Array arr && index >=0 && index < arr.Length) return arr.GetValue(index);
|
||
return null;
|
||
}
|
||
|
||
public override void Set(object target, object value)
|
||
{
|
||
if (target is System.Collections.IList list && index >= 0 && index < list.Count) list[index] = value;
|
||
else if (target is Array arr && index >=0 && index < arr.Length) arr.SetValue(value, index);
|
||
}
|
||
|
||
public override Type ReturnType => returnType ?? typeof(object);
|
||
public override bool IsValueType => ReturnType.IsValueType;
|
||
}
|
||
|
||
private PathNode[] nodes;
|
||
public bool IsValid { get; private set; }
|
||
|
||
public DeepAccessor(Type rootType, string path)
|
||
{
|
||
string[] parts = path.Split('.');
|
||
nodes = new PathNode[parts.Length];
|
||
Type currentType = rootType;
|
||
|
||
for (int i = 0; i < parts.Length; i++)
|
||
{
|
||
string part = parts[i];
|
||
|
||
// 数组/列表处理口
|
||
if (int.TryParse(part, out int idx))
|
||
{
|
||
nodes[i] = new IndexNode(idx, currentType);
|
||
currentType = nodes[i].ReturnType;
|
||
continue;
|
||
}
|
||
|
||
FieldInfo field = currentType.GetField(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||
if (field != null)
|
||
{
|
||
nodes[i] = new FieldNode(field);
|
||
currentType = field.FieldType;
|
||
continue;
|
||
}
|
||
|
||
PropertyInfo prop = currentType.GetProperty(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||
if (prop != null)
|
||
{
|
||
nodes[i] = new PropertyNode(prop);
|
||
currentType = prop.PropertyType;
|
||
continue;
|
||
}
|
||
|
||
// 路径断裂或找不到
|
||
IsValid = false;
|
||
return;
|
||
}
|
||
IsValid = true;
|
||
}
|
||
|
||
public object GetValue(object target)
|
||
{
|
||
if (!IsValid) return null;
|
||
object current = target;
|
||
for (int i = 0; i < nodes.Length; i++)
|
||
{
|
||
if (current == null) return null;
|
||
current = nodes[i].Get(current);
|
||
}
|
||
return current;
|
||
}
|
||
|
||
public void SetValue(object target, object value)
|
||
{
|
||
if (!IsValid || target == null) return;
|
||
SetRecursive(target, 0, value);
|
||
}
|
||
|
||
// 严丝合缝拦截所有嵌套 Struct 被传值拷贝吃掉而不回写的底层 C# 坑
|
||
private void SetRecursive(object currentObj, int index, object finalValue)
|
||
{
|
||
PathNode node = nodes[index];
|
||
|
||
if (index == nodes.Length - 1)
|
||
{
|
||
node.Set(currentObj, finalValue);
|
||
return;
|
||
}
|
||
|
||
object nextObj = node.Get(currentObj);
|
||
if (nextObj == null) return;
|
||
|
||
SetRecursive(nextObj, index + 1, finalValue);
|
||
|
||
if (node.IsValueType)
|
||
{
|
||
node.Set(currentObj, nextObj);
|
||
}
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
} |