PropertyPathResolver.cs 2.69 KB
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Rcs.Shared.Utils
{
    /// <summary>
    /// 属性路径解析器 - 支持点号分隔的嵌套属性访问
    /// @author zzy
    /// </summary>
    public static class PropertyPathResolver
    {
        /// <summary>
        /// 属性信息缓存,提升反射性能
        /// </summary>
        private static readonly Dictionary<(Type, string), PropertyInfo?> PropertyCache = new();
        private static readonly object CacheLock = new();

        /// <summary>
        /// 根据属性路径获取对象的属性值
        /// </summary>
        /// <param name="source">源对象</param>
        /// <param name="path">属性路径,支持点号分隔(如:Task.LoadType、Robot.MapNode.NodeCode)</param>
        /// <returns>属性值,如果路径无效则返回null</returns>
        public static object? GetValue(object? source, string path)
        {
            if (source == null || string.IsNullOrEmpty(path))
                return null;

            var current = source;
            var parts = path.Split('.');

            foreach (var part in parts)
            {
                if (current == null)
                    return null;

                var prop = GetCachedProperty(current.GetType(), part);
                if (prop == null)
                    return null;

                current = prop.GetValue(current);
            }

            return current;
        }

        /// <summary>
        /// 获取缓存的属性信息
        /// </summary>
        private static PropertyInfo? GetCachedProperty(Type type, string propertyName)
        {
            var key = (type, propertyName);

            lock (CacheLock)
            {
                if (PropertyCache.TryGetValue(key, out var cached))
                    return cached;

                var prop = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                PropertyCache[key] = prop;
                return prop;
            }
        }

        /// <summary>
        /// 尝试将值转换为指定类型
        /// </summary>
        public static object? ConvertValue(object? value, Type targetType)
        {
            if (value == null)
                return null;

            if (targetType.IsInstanceOfType(value))
                return value;

            try
            {
                // 处理可空类型
                var underlyingType = Nullable.GetUnderlyingType(targetType) ?? targetType;
                return Convert.ChangeType(value, underlyingType);
            }
            catch
            {
                return value;
            }
        }
    }
}