Reflect反射性能全面优化,新增基准测试报告 本次提交大幅提升 NewLife.Reflection 的 Reflect 扩展方法性能: - 新增静态委托缓存(属性/字段/方法/构造),读无锁,写时复制,极大减少反射调用开销 - 引入线程本地单态缓存,连续访问同一成员热路径仅需指针比较 - 扩展方法直达 DefaultReflect 核心实现,绕过接口分派 - 支持 IList/IDictionary 类型自动解析并缓存无参构造委托,基元类型预填充委托 - DbTable、CsvDb 等场景统一走 GetProperties(true) 缓存,提升高频场景性能 - 新增 ReflectBenchmark 基准测试和 Reflect性能测试.md 报告,验证各场景下性能提升(属性Get提升2.4倍,属性Set提升1.9倍,方法调用有参提升2.6倍,属性列表获取提升5.1倍且零分配) 整体优化使 Reflect 扩展方法在高频反射场景下性能远超原生 .NET 反射。石头 authored at 2026-03-17 19:04:29
diff --git a/Benchmark/ReflectBenchmarks/ReflectBenchmark.cs b/Benchmark/ReflectBenchmarks/ReflectBenchmark.cs
new file mode 100644
index 0000000..04327dc
--- /dev/null
+++ b/Benchmark/ReflectBenchmarks/ReflectBenchmark.cs
@@ -0,0 +1,165 @@
+using System.Linq.Expressions;
+using System.Reflection;
+using BenchmarkDotNet.Attributes;
+using NewLife.Reflection;
+
+namespace Benchmark.ReflectBenchmarks;
+
+/// <summary>测试用模型类</summary>
+internal class SampleModel
+{
+ public String Name { get; set; } = "";
+ public Int32 Age { get; set; }
+ public DateTime CreateTime { get; set; }
+
+ public String GetDisplayName() => $"{Name}({Age})";
+ public Int32 Add(Int32 a, Int32 b) => a + b;
+}
+
+/// <summary>Reflect 扩展与原始 .NET 反射性能对比基准测试</summary>
+[MemoryDiagnoser]
+[SimpleJob(iterationCount: 20)]
+public class ReflectBenchmark
+{
+ private PropertyInfo _pi = null!;
+ private MethodInfo _miNoParam = null!;
+ private MethodInfo _miWithParam = null!;
+ private Type _type = null!;
+ private SampleModel _model = null!;
+
+ // 预编译委托(用于 Baseline 对比)
+ private Func<Object?, Object?> _directGetter = null!;
+ private Action<Object?, Object?> _directSetter = null!;
+ private Func<Object> _directCtor = null!;
+ private Func<Object?, Object?> _directInvokeNoParam = null!;
+ private Func<Object?, Object?[]?, Object?> _directInvokeWithParam = null!;
+
+ private static readonly Object[] _invokeArgs = [3, 4];
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _type = typeof(SampleModel);
+ _pi = _type.GetProperty(nameof(SampleModel.Name))!;
+ _miNoParam = _type.GetMethod(nameof(SampleModel.GetDisplayName))!;
+ _miWithParam = _type.GetMethod(nameof(SampleModel.Add))!;
+ _model = new SampleModel { Name = "Hello", Age = 42, CreateTime = DateTime.Now };
+
+ // 预先编译直接委托(基准对比用,排除首次编译开销)
+ var obj = Expression.Parameter(typeof(Object), "obj");
+ var cast = Expression.Convert(obj, _type);
+ _directGetter = Expression.Lambda<Func<Object?, Object?>>(
+ Expression.Convert(Expression.Property(cast, _pi), typeof(Object)), obj).Compile();
+
+ var val = Expression.Parameter(typeof(Object), "val");
+ _directSetter = Expression.Lambda<Action<Object?, Object?>>(
+ Expression.Assign(Expression.Property(Expression.Convert(obj, _type), _pi),
+ Expression.Convert(val, _pi.PropertyType)), obj, val).Compile();
+
+ var ctor = _type.GetConstructor(Type.EmptyTypes)!;
+ _directCtor = Expression.Lambda<Func<Object>>(Expression.New(ctor)).Compile();
+
+ // 0-param 直接 Func<Object?,Object?> 委托(不含 Object[] 数组开销)
+ _directInvokeNoParam = Expression.Lambda<Func<Object?, Object?>>(
+ Expression.Convert(Expression.Call(Expression.Convert(obj, _type), _miNoParam), typeof(Object)),
+ obj).Compile();
+
+ var argsParam = Expression.Parameter(typeof(Object?[]), "args");
+ _directInvokeWithParam = Expression.Lambda<Func<Object?, Object?[]?, Object?>>(
+ Expression.Convert(
+ Expression.Call(Expression.Convert(obj, _type), _miWithParam,
+ Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(0)), typeof(Int32)),
+ Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(1)), typeof(Int32))),
+ typeof(Object)),
+ obj, argsParam).Compile();
+
+ // 预热 NewLife 缓存(排除首次编译开销)
+ _ = _model.GetValue((MemberInfo)_pi);
+ _model.SetValue((MemberInfo)_pi, "Warmup");
+ _ = _type.CreateInstance();
+ _ = _type.GetProperties(true);
+ _ = _model.Invoke(_miNoParam, (Object?[]?)null);
+ _ = _model.Invoke(_miWithParam, _invokeArgs);
+ // 同时预热 Provider 直调路径
+ _ = Reflect.Provider.GetValue(_model, _pi);
+ Reflect.Provider.SetValue(_model, _pi, "Warmup");
+ _ = Reflect.Provider.Invoke(_model, _miNoParam, null);
+ _ = Reflect.Provider.Invoke(_model, _miWithParam, _invokeArgs);
+ }
+
+ #region 属性 Get
+ [Benchmark(Description = "属性Get-原始反射")]
+ public Object? RawPropertyGet() => _pi.GetValue(_model, null);
+
+ [Benchmark(Description = "属性Get-直接Lambda")]
+ public Object? DirectLambdaGet() => _directGetter(_model);
+
+ [Benchmark(Description = "属性Get-Provider直调")]
+ public Object? ProviderPropertyGet() => Reflect.Provider.GetValue(_model, _pi);
+
+ [Benchmark(Description = "属性Get-扩展方法")]
+ public Object? ExtMethodPropertyGet() => _model.GetValue((MemberInfo)_pi);
+ #endregion
+
+ #region 属性 Set
+ [Benchmark(Description = "属性Set-原始反射")]
+ public void RawPropertySet() => _pi.SetValue(_model, "World", null);
+
+ [Benchmark(Description = "属性Set-直接Lambda")]
+ public void DirectLambdaSet() => _directSetter(_model, "World");
+
+ [Benchmark(Description = "属性Set-Provider直调")]
+ public void ProviderPropertySet() => Reflect.Provider.SetValue(_model, _pi, "World");
+
+ [Benchmark(Description = "属性Set-扩展方法")]
+ public void ExtMethodPropertySet() => _model.SetValue((MemberInfo)_pi, "World");
+ #endregion
+
+ #region CreateInstance
+ [Benchmark(Description = "CreateInstance-Activator")]
+ public Object ActivatorCreate() => Activator.CreateInstance(_type)!;
+
+ [Benchmark(Description = "CreateInstance-直接Lambda")]
+ public Object DirectLambdaCreate() => _directCtor();
+
+ [Benchmark(Description = "CreateInstance-扩展方法")]
+ public Object? NewLifeCreate() => _type.CreateInstance();
+ #endregion
+
+ #region Invoke(无参数)
+ [Benchmark(Description = "Invoke无参-原始反射")]
+ public Object? RawInvokeNoParam() => _miNoParam.Invoke(_model, null);
+
+ [Benchmark(Description = "Invoke无参-直接Lambda")]
+ public Object? DirectLambdaInvokeNoParam() => _directInvokeNoParam(_model);
+
+ [Benchmark(Description = "Invoke无参-Provider直调")]
+ public Object? ProviderInvokeNoParam() => Reflect.Provider.Invoke(_model, _miNoParam, null);
+
+ [Benchmark(Description = "Invoke无参-扩展方法")]
+ public Object? ExtMethodInvokeNoParam() => _model.Invoke(_miNoParam, (Object?[]?)null);
+ #endregion
+
+ #region Invoke(带参数)
+ [Benchmark(Description = "Invoke带参-原始反射")]
+ public Object? RawInvokeWithParam() => _miWithParam.Invoke(_model, _invokeArgs);
+
+ [Benchmark(Description = "Invoke带参-直接Lambda")]
+ public Object? DirectLambdaInvokeWithParam() => _directInvokeWithParam(_model, _invokeArgs);
+
+ [Benchmark(Description = "Invoke带参-Provider直调")]
+ public Object? ProviderInvokeWithParam() => Reflect.Provider.Invoke(_model, _miWithParam, _invokeArgs);
+
+ [Benchmark(Description = "Invoke带参-扩展方法")]
+ public Object? ExtMethodInvokeWithParam() => _model.Invoke(_miWithParam, _invokeArgs);
+ #endregion
+
+ #region GetProperties
+ [Benchmark(Description = "GetProperties-原始反射")]
+ public PropertyInfo[] RawGetProperties() => _type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ [Benchmark(Description = "GetProperties-扩展方法缓存")]
+ public IList<PropertyInfo> CachedGetProperties() => _type.GetProperties(true);
+ #endregion
+}
+
diff --git "a/Doc/Benchmark/Reflect\346\200\247\350\203\275\346\265\213\350\257\225.md" "b/Doc/Benchmark/Reflect\346\200\247\350\203\275\346\265\213\350\257\225.md"
new file mode 100644
index 0000000..25b8732
--- /dev/null
+++ "b/Doc/Benchmark/Reflect\346\200\247\350\203\275\346\265\213\350\257\225.md"
@@ -0,0 +1,51 @@
+# Reflect 性能测试报告
+
+## 测试环境
+
+```
+BenchmarkDotNet v0.15.8,Windows 10 (10.0.19045.6456/22H2)
+Intel Core i9-10900K CPU 3.70GHz,20 逻辑核 / 10 物理核
+.NET SDK 10.0.104 / Runtime .NET 10.0.4,X64 RyuJIT x86-64-v3
+IterationCount=20,Release 模式
+```
+
+## 测试结果
+
+对比 `Reflect` 扩展方法(用户侧 API)与等价原始 .NET 反射调用的耗时和内存分配。
+
+| 场景 | 原始反射 | Reflect 扩展方法 | 提升倍数 | 内存分配 |
+|------|---------|-----------------|---------|---------|
+| 属性 Get | 5.96 ns | **2.45 ns** | **2.4x** | 零分配(两者相同) |
+| 属性 Set | 11.42 ns | **6.16 ns** | **1.9x** | 零分配(两者相同) |
+| 创建实例 | 7.12 ns(Activator) | **5.81 ns** | **1.2x** | 两者均 40 B |
+| 方法调用(无参) | 28.62 ns | **26.71 ns** | **1.1x** | 两者均 48 B |
+| 方法调用(有参) | 19.44 ns | **7.52 ns** | **2.6x** | 两者均 24 B |
+| 获取属性列表 | 23.97 ns,48 B | **4.68 ns** | **5.1x** | **零分配** |
+
+> 原始数据:`属性Get-原始反射 5.9596 ns`、`属性Get-扩展方法 2.4522 ns`、`属性Set-原始反射 11.4165 ns`、`属性Set-扩展方法 6.1593 ns`、`CreateInstance-Activator 7.1203 ns`、`CreateInstance-扩展方法 5.8080 ns`、`Invoke无参-原始反射 28.6235 ns`、`Invoke无参-扩展方法 26.7132 ns`、`Invoke带参-原始反射 19.4416 ns`、`Invoke带参-扩展方法 7.5211 ns`、`GetProperties-原始反射 23.9717 ns / 48B`、`GetProperties-扩展方法缓存 4.6842 ns / 0B`
+
+## 性能分析
+
+### 为什么 Reflect 扩展方法快于原始反射?
+
+原始 .NET 反射(`PropertyInfo.GetValue`、`MethodInfo.Invoke` 等)每次调用都要经过参数校验、安全检查、装箱/拆箱和动态分派,本质是通用路径,没有任何针对具体类型的优化。
+
+`Reflect` 扩展方法采用三层加速结构:
+
+1. **Lambda 编译缓存**:首次调用时为目标成员编译强类型委托(`Expression.Lambda.Compile()`),后续调用直接执行机器码,省去反射的通用路径开销。
+
+2. **静态 COW 字典**:编译后的委托存入 Copy-on-Write 字典,读路径无锁,并发安全。`TryGetValue` 在已缓存时约 3 ns 即可取到委托。
+
+3. **线程本地单态内联缓存**:每个线程维护最近一次调用的成员引用 + 委托,连续访问同一成员时只需一次指针比较(~0.3 ns),完全跳过字典查找。这是属性 Get 从 5.96 ns 降至 2.45 ns 的主要原因。
+
+### 各场景解读
+
+**属性 Get / Set(2.4x / 1.9x)**:原始反射每次走完整校验路径;扩展方法热路径为"指针比较 → 委托调用",已接近直接属性访问的理论下限。Set 额外含一次类型判断(`value.GetType() == propertyType`),因此略慢于 Get。
+
+**方法调用有参(2.6x)**:原始 `MethodInfo.Invoke` 需要装箱参数并分配 `Object[]`;扩展方法的强类型委托直接传递参数,省去装箱和数组开销,因此提升最为显著。
+
+**方法调用无参(1.1x)**:提升较小,因为被测方法体本身含字符串插值(`$"{Name}({Age})"`),约 23 ns 的方法本体开销远大于调用开销,反射层面的差异被稀释。
+
+**创建实例(1.2x)**:`Activator.CreateInstance` 内部已有优化,提升空间有限;扩展方法通过缓存无参构造委托,主要节省类型查找和安全检查的固定成本。
+
+**获取属性列表(5.1x,零分配)**:原始 `Type.GetProperties()` 每次都分配新数组(48 B)并遍历反射元数据;扩展方法将结果缓存为 `IList<PropertyInfo>`,热路径只读缓存,零分配,是提升最大的场景。
diff --git a/NewLife.Core/Data/DbTable.cs b/NewLife.Core/Data/DbTable.cs
index c6ab34c..f2f9e8a 100644
--- a/NewLife.Core/Data/DbTable.cs
+++ b/NewLife.Core/Data/DbTable.cs
@@ -80,29 +80,66 @@ public class DbTable : IEnumerable<DbRow>, ICloneable, IAccessor, ISpanSerializa
if (fields == null || fields.Length == 0)
fields = Enumerable.Range(0, cs.Length).ToArray();
+ // 检测读取器是否支持 TakeValues 快速读取(如 NewLife.MySql 等特殊读取器)
+ // 仅在顺序映射(fields[i]==i)时可直接窃取行数组,无需新建 Object?[] 也无需逐列索引
+ Func<Object?[]?>? takeValues = null;
+ if (fields.Length == ts.Length)
+ {
+ var tvMethod = dr.GetType().GetMethod("TakeValues", Type.EmptyTypes);
+ if (tvMethod != null)
+ {
+ var isIdentity = true;
+ for (var i = 0; i < fields.Length; i++)
+ {
+ if (fields[i] != i) { isIdentity = false; break; }
+ }
+ if (isIdentity)
+ takeValues = tvMethod.As<Func<Object?[]?>>(dr);
+ }
+ }
+
// 数据
var rs = new List<Object?[]>();
- while (dr.Read())
+ if (takeValues != null)
{
- var row = new Object?[fields.Length];
- for (var i = 0; i < fields.Length; i++)
+ while (dr.Read())
{
- // MySql在读取0000时间数据时会报错
- try
- {
- var idx = fields[i];
- var val = dr[idx];
+ var row = takeValues();
+ if (row == null) continue;
- if (val == DBNull.Value)
+ // 原地修复 DBNull,按目标列类型填充默认值
+ for (var i = 0; i < ts.Length && i < row.Length; i++)
+ {
+ if (row[i] == DBNull.Value)
+ row[i] = GetDefault(ts[i].GetTypeCode());
+ }
+ rs.Add(row!);
+ }
+ }
+ else
+ {
+ while (dr.Read())
+ {
+ var row = new Object?[fields.Length];
+ for (var i = 0; i < fields.Length; i++)
+ {
+ // MySql在读取0000时间数据时会报错
+ try
{
- // 按目标列 i 的类型填充默认值
- val = GetDefault(ts[i].GetTypeCode());
+ var idx = fields[i];
+ var val = dr[idx];
+
+ if (val == DBNull.Value)
+ {
+ // 按目标列 i 的类型填充默认值
+ val = GetDefault(ts[i].GetTypeCode());
+ }
+ row[i] = val;
}
- row[i] = val;
+ catch { }
}
- catch { }
+ rs.Add(row);
}
- rs.Add(row);
}
Rows = rs;
@@ -130,29 +167,64 @@ public class DbTable : IEnumerable<DbRow>, ICloneable, IAccessor, ISpanSerializa
fields ??= Enumerable.Range(0, cs.Length).ToArray();
+ // 检测读取器是否支持 TakeValues 快速读取(如 NewLife.MySql 等特殊读取器)
+ Func<Object?[]?>? takeValues = null;
+ if (fields.Length == ts.Length)
+ {
+ var tvMethod = dr.GetType().GetMethod("TakeValues", Type.EmptyTypes);
+ if (tvMethod != null)
+ {
+ var isIdentity = true;
+ for (var i = 0; i < fields.Length; i++)
+ {
+ if (fields[i] != i) { isIdentity = false; break; }
+ }
+ if (isIdentity)
+ takeValues = tvMethod.As<Func<Object?[]?>>(dr);
+ }
+ }
+
// 数据
var rs = new List<Object?[]>();
- while (await dr.ReadAsync(cancellationToken).ConfigureAwait(false))
+ if (takeValues != null)
{
- var row = new Object?[fields.Length];
- for (var i = 0; i < fields.Length; i++)
+ while (await dr.ReadAsync(cancellationToken).ConfigureAwait(false))
{
- // MySql在读取0000时间数据时会报错
- try
- {
- var idx = fields[i];
- var val = dr[idx];
+ var row = takeValues();
+ if (row == null) continue;
- if (val == DBNull.Value)
+ for (var i = 0; i < ts.Length && i < row.Length; i++)
+ {
+ if (row[i] == DBNull.Value)
+ row[i] = GetDefault(ts[i].GetTypeCode());
+ }
+ rs.Add(row!);
+ }
+ }
+ else
+ {
+ while (await dr.ReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ var row = new Object?[fields.Length];
+ for (var i = 0; i < fields.Length; i++)
+ {
+ // MySql在读取0000时间数据时会报错
+ try
{
- // 按目标列 i 的类型填充默认值
- val = GetDefault(ts[i].GetTypeCode());
+ var idx = fields[i];
+ var val = dr[idx];
+
+ if (val == DBNull.Value)
+ {
+ // 按目标列 i 的类型填充默认值
+ val = GetDefault(ts[i].GetTypeCode());
+ }
+ row[i] = val;
}
- row[i] = val;
+ catch { }
}
- catch { }
+ rs.Add(row);
}
- rs.Add(row);
}
Rows = rs;
@@ -926,8 +998,8 @@ public class DbTable : IEnumerable<DbRow>, ICloneable, IAccessor, ISpanSerializa
var rows = Rows;
if (rows == null) yield break;
- // 可用属性
- var pis = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ // 可用属性(通过 DefaultReflect 缓存,避免重复反射扫描)
+ var pis = type.GetProperties(true);
var dic = pis.ToDictionary(e => SerialHelper.GetName(e), e => e, StringComparer.OrdinalIgnoreCase);
foreach (var row in rows)
diff --git a/NewLife.Core/IO/CsvDb.cs b/NewLife.Core/IO/CsvDb.cs
index a865e44..c1977ef 100644
--- a/NewLife.Core/IO/CsvDb.cs
+++ b/NewLife.Core/IO/CsvDb.cs
@@ -22,7 +22,8 @@ public class CsvDb<T> : DisposeBase where T : new()
{
#region 静态缓存(反射开销优化)
// 只反射一次,降低读写频率较高场景的成本
- private static readonly PropertyInfo[] _properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ // 使用 GetProperties(true) 走 DefaultReflect 缓存,同时过滤 XmlIgnore/IgnoreDataMember 等特性
+ private static readonly IList<PropertyInfo> _properties = typeof(T).GetProperties(true);
// 统一使用序列化名(可能来自特性),修复原先头部写入使用属性名导致与读取不一致的缺陷
private static readonly String[] _propertyNames = _properties.Select(SerialHelper.GetName).ToArray();
// 属性名到索引的映射,用于快速查找
diff --git a/NewLife.Core/Reflection/IReflect.cs b/NewLife.Core/Reflection/IReflect.cs
index c3b9ccd..35853ab 100644
--- a/NewLife.Core/Reflection/IReflect.cs
+++ b/NewLife.Core/Reflection/IReflect.cs
@@ -1,7 +1,9 @@
using System.Collections;
using System.Collections.Concurrent;
using System.ComponentModel;
+using System.Linq.Expressions;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
@@ -433,75 +435,139 @@ public class DefaultReflect : IReflect
#endregion
#region 反射调用
+ // 写时复制字典(全部为静态):热路径仅需一次静态 volatile 读 + Dictionary.TryGetValue,无锁无CAS;
+ // 静态字段使 Reflect.cs 扩展方法可直接访问,省去 _directProvider volatile 读 + 接口分派(约 2 ns);
+ // 冷路径在 lock 内生成新快照后原子发布,首次编译后后续调用开销极低
+ internal static volatile Dictionary<PropertyInfo, Func<Object?, Object?>?> _propGetterDict = [];
+ internal static volatile Dictionary<PropertyInfo, Action<Object?, Object?>?> _propSetterDict = [];
+ internal static volatile Dictionary<FieldInfo, Func<Object?, Object?>?> _fieldGetterDict = [];
+ internal static volatile Dictionary<FieldInfo, Action<Object?, Object?>?> _fieldSetterDict = [];
+ // 0-param 专用缓存:Func<Object?,Object?> 省去 Object[] 参数数组开销
+ internal static volatile Dictionary<MethodInfo, Func<Object?, Object?>?> _invoker0Dict = [];
+ // N-param 通用缓存:Func<Object?,Object?[]?,Object?>
+ internal static volatile Dictionary<MethodInfo, Func<Object?, Object?[]?, Object?>?> _invokerNDict = [];
+ internal static volatile Dictionary<Type, Func<Object>?> _instanceFactoryDict = BuildPrimitiveFactories();
+ private static readonly Object _cacheLock = new();
+
+ // 预填充基元类型工厂委托,捕获缓存装箱对象避免每次 CreateInstance 重复分配
+ private static Dictionary<Type, Func<Object>?> BuildPrimitiveFactories()
+ {
+ Object boxFalse = false, boxChar0 = '\0', boxSByte0 = (SByte)0, boxByte0 = (Byte)0;
+ Object boxI160 = (Int16)0, boxU160 = (UInt16)0, boxI320 = 0, boxU320 = 0U;
+ Object boxI640 = 0L, boxU640 = 0UL, boxF0 = 0F, boxD0 = 0D, boxM0 = 0M;
+ Object boxDt = DateTime.MinValue;
+ return new()
+ {
+ [typeof(Boolean)] = () => boxFalse,
+ [typeof(Char)] = () => boxChar0,
+ [typeof(SByte)] = () => boxSByte0,
+ [typeof(Byte)] = () => boxByte0,
+ [typeof(Int16)] = () => boxI160,
+ [typeof(UInt16)] = () => boxU160,
+ [typeof(Int32)] = () => boxI320,
+ [typeof(UInt32)] = () => boxU320,
+ [typeof(Int64)] = () => boxI640,
+ [typeof(UInt64)] = () => boxU640,
+ [typeof(Single)] = () => boxF0,
+ [typeof(Double)] = () => boxD0,
+ [typeof(Decimal)] = () => boxM0,
+ [typeof(DateTime)] = () => boxDt,
+ [typeof(String)] = static () => String.Empty,
+ };
+ }
+
/// <summary>反射创建指定类型的实例</summary>
/// <param name="type">类型</param>
/// <param name="parameters">参数数组</param>
/// <returns></returns>
- public virtual Object? CreateInstance(Type type, params Object?[] parameters)
+ public virtual Object? CreateInstance(Type type, params Object?[] parameters) => CreateInstanceCore(type, parameters);
+
+ // 非虚核心实现,供 Reflect.cs 直接调用
+ internal Object? CreateInstanceCore(Type type, Object?[]? parameters)
{
try
{
- var code = type.GetTypeCode();
-
- // 列表
- if (code == TypeCode.Object && (type.As<IList>() || type.As(typeof(IList<>))))
+ if (parameters == null || parameters.Length == 0)
{
- var type2 = type;
- if (type2.IsInterface)
- {
- if (type2.IsGenericType)
- type2 = typeof(List<>).MakeGenericType(type2.GetGenericArguments());
- else if (type2 == typeof(IList))
- type2 = typeof(List<Object>);
- }
- return Activator.CreateInstance(type2);
+ // 热路径:已缓存的工厂委托,绕过所有 TypeCode/IList/IDictionary 预检
+ if (_instanceFactoryDict.TryGetValue(type, out var factory))
+ return factory != null ? factory() : Activator.CreateInstance(type, true);
+
+ return RegisterAndCreate(type);
}
+ return Activator.CreateInstance(type, parameters);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"Fail to create object type={type.FullName} parameters={parameters?.Join()} {ex.GetTrue()?.Message}", ex);
+ }
+ }
- // 字典
- if (code == TypeCode.Object && (type.As<IDictionary>() || type.As(typeof(IDictionary<,>))))
+ // 冷路径:首次为该类型生成工厂并注册到缓存
+ private Object? RegisterAndCreate(Type type)
+ {
+ Func<Object>? factory;
+ var code = type.GetTypeCode();
+ if (code != TypeCode.Object)
+ {
+ // 枚举等 TypeCode 非 Object 类型(基元已在 BuildPrimitiveFactories 预填充,此处兜底)
+ factory = code switch
+ {
+ TypeCode.Boolean => static () => false,
+ TypeCode.Char => static () => '\0',
+ TypeCode.SByte => static () => (SByte)0,
+ TypeCode.Byte => static () => (Byte)0,
+ TypeCode.Int16 => static () => (Int16)0,
+ TypeCode.UInt16 => static () => (UInt16)0,
+ TypeCode.Int32 => static () => 0,
+ TypeCode.UInt32 => static () => 0U,
+ TypeCode.Int64 => static () => 0L,
+ TypeCode.UInt64 => static () => 0UL,
+ TypeCode.Single => static () => 0F,
+ TypeCode.Double => static () => 0D,
+ TypeCode.Decimal => static () => 0M,
+ TypeCode.DateTime => static () => DateTime.MinValue,
+ TypeCode.String => static () => String.Empty,
+ _ => null,
+ };
+ }
+ else
+ {
+ // IList / IDictionary 接口解析(冷路径,仅首次调用该接口类型)
+ var targetType = type;
+ if (type.IsInterface || type.IsAbstract)
{
- var type2 = type;
- if (type2.IsInterface)
+ if (type.As<IList>() || type.As(typeof(IList<>)))
{
- if (type2.IsGenericType)
- type2 = typeof(Dictionary<,>).MakeGenericType(type2.GetGenericArguments());
- else if (type2 == typeof(IDictionary))
- type2 = typeof(Dictionary<Object, Object>);
+ if (type.IsGenericType)
+ targetType = typeof(List<>).MakeGenericType(type.GetGenericArguments());
+ else if (type == typeof(IList))
+ targetType = typeof(List<Object>);
}
- return Activator.CreateInstance(type2);
- }
-
- if (parameters == null || parameters.Length == 0)
- {
- // 基元类型
- return code switch
+ else if (type.As<IDictionary>() || type.As(typeof(IDictionary<,>)))
{
- //TypeCode.Empty or TypeCode.DBNull => null,
- TypeCode.Boolean => false,
- TypeCode.Char => '\0',
- TypeCode.SByte => (SByte)0,
- TypeCode.Byte => (Byte)0,
- TypeCode.Int16 => (Int16)0,
- TypeCode.UInt16 => (UInt16)0,
- TypeCode.Int32 => 0,
- TypeCode.UInt32 => 0U,
- TypeCode.Int64 => 0L,
- TypeCode.UInt64 => 0UL,
- TypeCode.Single => 0F,
- TypeCode.Double => 0D,
- TypeCode.Decimal => 0M,
- TypeCode.DateTime => DateTime.MinValue,
- TypeCode.String => String.Empty,
- _ => Activator.CreateInstance(type, true),
- };
+ if (type.IsGenericType)
+ targetType = typeof(Dictionary<,>).MakeGenericType(type.GetGenericArguments());
+ else if (type == typeof(IDictionary))
+ targetType = typeof(Dictionary<Object, Object>);
+ }
}
- else
- return Activator.CreateInstance(type, parameters);
+
+ var ctor = targetType.GetConstructor(Type.EmptyTypes);
+ factory = ctor != null ? Expression.Lambda<Func<Object>>(Expression.New(ctor)).Compile() : null;
}
- catch (Exception ex)
+
+ // 写时复制发布(lock 保证唯一写入,volatile 保证所有读者可见)
+ lock (_cacheLock)
{
- throw new Exception($"Fail to create object type={type.FullName} parameters={parameters?.Join()} {ex.GetTrue()?.Message}", ex);
+ if (!_instanceFactoryDict.ContainsKey(type))
+ {
+ var next = new Dictionary<Type, Func<Object>?>(_instanceFactoryDict) { [type] = factory };
+ _instanceFactoryDict = next;
+ }
}
+
+ return factory != null ? factory() : Activator.CreateInstance(type, true);
}
/// <summary>反射调用指定对象的方法</summary>
@@ -509,7 +575,116 @@ public class DefaultReflect : IReflect
/// <param name="method">方法</param>
/// <param name="parameters">方法参数</param>
/// <returns></returns>
- public virtual Object? Invoke(Object? target, MethodBase method, Object?[]? parameters) => method.Invoke(target, parameters);
+ public virtual Object? Invoke(Object? target, MethodBase method, Object?[]? parameters) => InvokeCore(target, method, parameters);
+
+ // 非虚核心实现,供 Reflect.cs 直接调用绕过接口分派
+ internal Object? InvokeCore(Object? target, MethodBase method, Object?[]? parameters)
+ {
+ if (method is MethodInfo mi)
+ {
+ if (parameters == null || parameters.Length == 0)
+ {
+ // 0-param 专用路径:省去 Object[] 传递开销
+ var dict0 = _invoker0Dict;
+ if (!dict0.TryGetValue(mi, out var inv0))
+ inv0 = AddInvoker0(mi);
+ if (inv0 != null)
+ return inv0(target);
+ }
+ else
+ {
+ // N-param 通用路径
+ var dictN = _invokerNDict;
+ if (!dictN.TryGetValue(mi, out var invN))
+ invN = AddInvokerN(mi);
+ if (invN != null)
+ return invN(target, parameters);
+ }
+ }
+ return method.Invoke(target, parameters);
+ }
+
+ // 冷路径:为 0-param 方法编译 Func<Object?,Object?> 委托(省去 Object[] 参数开销)
+ internal Func<Object?, Object?>? AddInvoker0(MethodInfo method)
+ {
+ Func<Object?, Object?>? invoker = null;
+ try
+ {
+ if (!method.IsGenericMethod && method.DeclaringType != null && method.GetParameters().Length == 0)
+ {
+ var instanceParam = Expression.Parameter(typeof(Object), "instance");
+ Expression callExpr = method.IsStatic
+ ? Expression.Call(method)
+ : Expression.Call(Expression.Convert(instanceParam, method.DeclaringType), method);
+ var resultExpr = method.ReturnType == typeof(void)
+ ? (Expression)Expression.Block(typeof(Object), callExpr, Expression.Constant(null, typeof(Object)))
+ : Expression.Convert(callExpr, typeof(Object));
+ invoker = Expression.Lambda<Func<Object?, Object?>>(resultExpr, instanceParam).Compile();
+ }
+ }
+ catch { invoker = null; }
+
+ lock (_cacheLock)
+ {
+ if (!_invoker0Dict.ContainsKey(method))
+ {
+ var next = new Dictionary<MethodInfo, Func<Object?, Object?>?>(_invoker0Dict) { [method] = invoker };
+ _invoker0Dict = next;
+ }
+ }
+ return invoker;
+ }
+
+ // 冷路径:为 N-param 方法编译 Func<Object?,Object?[]?,Object?> 委托
+ internal Func<Object?, Object?[]?, Object?>? AddInvokerN(MethodInfo method)
+ {
+ Func<Object?, Object?[]?, Object?>? invoker;
+ try
+ {
+ if (method.IsGenericMethod || method.DeclaringType == null)
+ {
+ invoker = null;
+ }
+ else
+ {
+ var pis = method.GetParameters();
+ // 含 ref/out 参数时回退原始反射
+ if (Array.Exists(pis, static p => p.ParameterType.IsByRef))
+ {
+ invoker = null;
+ }
+ else
+ {
+ var instanceParam = Expression.Parameter(typeof(Object), "instance");
+ var argsParam = Expression.Parameter(typeof(Object?[]), "args");
+ var argExprs = new Expression[pis.Length];
+ for (var i = 0; i < pis.Length; i++)
+ argExprs[i] = Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(i)), pis[i].ParameterType);
+
+ Expression callExpr = method.IsStatic
+ ? Expression.Call(method, argExprs)
+ : Expression.Call(Expression.Convert(instanceParam, method.DeclaringType), method, argExprs);
+
+ var resultExpr = method.ReturnType == typeof(void)
+ ? (Expression)Expression.Block(typeof(Object), callExpr, Expression.Constant(null, typeof(Object)))
+ : Expression.Convert(callExpr, typeof(Object));
+
+ invoker = Expression.Lambda<Func<Object?, Object?[]?, Object?>>(resultExpr, instanceParam, argsParam).Compile();
+ }
+ }
+ }
+ catch { invoker = null; }
+
+ lock (_cacheLock)
+ {
+ if (!_invokerNDict.ContainsKey(method))
+ {
+ var next = new Dictionary<MethodInfo, Func<Object?, Object?[]?, Object?>?>(_invokerNDict) { [method] = invoker };
+ _invokerNDict = next;
+ }
+ }
+ return invoker;
+ }
/// <summary>反射调用指定对象的方法</summary>
/// <param name="target">要调用其方法的对象,如果要调用静态方法,则target是类型</param>
@@ -531,32 +706,194 @@ public class DefaultReflect : IReflect
ps[i] = v.ChangeType(pis[i].ParameterType);
}
- return method.Invoke(target, ps);
+ return Invoke(target, method, ps);
}
/// <summary>获取目标对象的属性值</summary>
/// <param name="target">目标对象</param>
/// <param name="property">属性</param>
/// <returns></returns>
- public virtual Object? GetValue(Object? target, PropertyInfo property) => property.GetValue(target, null);
+ public virtual Object? GetValue(Object? target, PropertyInfo property) => GetValueCore(target, property);
+
+ // 非虚核心实现,供 Reflect.cs 直接调用绕过接口分派
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Object? GetValueCore(Object? target, PropertyInfo property)
+ {
+ var dict = _propGetterDict;
+ if (!dict.TryGetValue(property, out var getter))
+ getter = AddPropGetter(property);
+ return getter != null ? getter(target) : property.GetValue(target, null);
+ }
+
+ // 冷路径:编译并缓存属性 getter
+ internal Func<Object?, Object?>? AddPropGetter(PropertyInfo pi)
+ {
+ Func<Object?, Object?>? getter;
+ if (pi.GetGetMethod(true)?.IsStatic == true)
+ {
+ getter = null;
+ }
+ else
+ {
+ var obj = Expression.Parameter(typeof(Object), "obj");
+ getter = Expression.Lambda<Func<Object?, Object?>>(
+ Expression.Convert(Expression.Property(Expression.Convert(obj, pi.DeclaringType!), pi), typeof(Object)), obj).Compile();
+ }
+
+ lock (_cacheLock)
+ {
+ if (!_propGetterDict.ContainsKey(pi))
+ {
+ var next = new Dictionary<PropertyInfo, Func<Object?, Object?>?>(_propGetterDict) { [pi] = getter };
+ _propGetterDict = next;
+ }
+ }
+ return getter;
+ }
/// <summary>获取目标对象的字段值</summary>
/// <param name="target">目标对象</param>
/// <param name="field">字段</param>
/// <returns></returns>
- public virtual Object? GetValue(Object? target, FieldInfo field) => field.GetValue(target);
+ public virtual Object? GetValue(Object? target, FieldInfo field) => GetValueFieldCore(target, field);
+
+ // 非虚核心实现
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Object? GetValueFieldCore(Object? target, FieldInfo field)
+ {
+ var dict = _fieldGetterDict;
+ if (!dict.TryGetValue(field, out var getter))
+ getter = AddFieldGetter(field);
+ return getter != null ? getter(target) : field.GetValue(target);
+ }
+
+ // 冷路径:编译并缓存字段 getter
+ internal Func<Object?, Object?>? AddFieldGetter(FieldInfo fi)
+ {
+ Func<Object?, Object?>? getter;
+ if (fi.IsStatic)
+ {
+ getter = null;
+ }
+ else
+ {
+ var obj = Expression.Parameter(typeof(Object), "obj");
+ getter = Expression.Lambda<Func<Object?, Object?>>(
+ Expression.Convert(Expression.Field(Expression.Convert(obj, fi.DeclaringType!), fi), typeof(Object)), obj).Compile();
+ }
+
+ lock (_cacheLock)
+ {
+ if (!_fieldGetterDict.ContainsKey(fi))
+ {
+ var next = new Dictionary<FieldInfo, Func<Object?, Object?>?>(_fieldGetterDict) { [fi] = getter };
+ _fieldGetterDict = next;
+ }
+ }
+ return getter;
+ }
/// <summary>设置目标对象的属性值</summary>
/// <param name="target">目标对象</param>
/// <param name="property">属性</param>
/// <param name="value">数值</param>
- public virtual void SetValue(Object target, PropertyInfo property, Object? value) => property.SetValue(target, value.ChangeType(property.PropertyType), null);
+ public virtual void SetValue(Object target, PropertyInfo property, Object? value) => SetValueCore(target, property, value);
+
+ // 非虚核心实现
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void SetValueCore(Object target, PropertyInfo property, Object? value)
+ {
+ var pt = property.PropertyType;
+ var converted = value == null || value.GetType() == pt ? value : value.ChangeType(pt);
+ var dict = _propSetterDict;
+ if (!dict.TryGetValue(property, out var setter))
+ setter = AddPropSetter(property);
+ if (setter != null)
+ setter(target, converted);
+ else
+ property.SetValue(target, converted, null);
+ }
+
+ // 冷路径:编译并缓存属性 setter
+ internal Action<Object?, Object?>? AddPropSetter(PropertyInfo pi)
+ {
+ Action<Object?, Object?>? setter;
+ if (!pi.CanWrite || pi.DeclaringType?.IsValueType == true || pi.GetSetMethod(true)?.IsStatic == true)
+ {
+ setter = null;
+ }
+ else
+ {
+ var obj = Expression.Parameter(typeof(Object), "obj");
+ var val = Expression.Parameter(typeof(Object), "val");
+ setter = Expression.Lambda<Action<Object?, Object?>>(
+ Expression.Assign(
+ Expression.Property(Expression.Convert(obj, pi.DeclaringType!), pi),
+ Expression.Convert(val, pi.PropertyType)),
+ obj, val).Compile();
+ }
+
+ lock (_cacheLock)
+ {
+ if (!_propSetterDict.ContainsKey(pi))
+ {
+ var next = new Dictionary<PropertyInfo, Action<Object?, Object?>?>(_propSetterDict) { [pi] = setter };
+ _propSetterDict = next;
+ }
+ }
+ return setter;
+ }
/// <summary>设置目标对象的字段值</summary>
/// <param name="target">目标对象</param>
/// <param name="field">字段</param>
/// <param name="value">数值</param>
- public virtual void SetValue(Object target, FieldInfo field, Object? value) => field.SetValue(target, value.ChangeType(field.FieldType));
+ public virtual void SetValue(Object target, FieldInfo field, Object? value) => SetValueFieldCore(target, field, value);
+
+ // 非虚核心实现
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void SetValueFieldCore(Object target, FieldInfo field, Object? value)
+ {
+ var ft = field.FieldType;
+ var converted = value == null || value.GetType() == ft ? value : value.ChangeType(ft);
+ var dict = _fieldSetterDict;
+ if (!dict.TryGetValue(field, out var setter))
+ setter = AddFieldSetter(field);
+ if (setter != null)
+ setter(target, converted);
+ else
+ field.SetValue(target, converted);
+ }
+
+ // 冷路径:编译并缓存字段 setter
+ internal Action<Object?, Object?>? AddFieldSetter(FieldInfo fi)
+ {
+ Action<Object?, Object?>? setter;
+ if (fi.IsInitOnly || fi.IsLiteral || fi.DeclaringType?.IsValueType == true || fi.IsStatic)
+ {
+ setter = null;
+ }
+ else
+ {
+ var obj = Expression.Parameter(typeof(Object), "obj");
+ var val = Expression.Parameter(typeof(Object), "val");
+ setter = Expression.Lambda<Action<Object?, Object?>>(
+ Expression.Assign(
+ Expression.Field(Expression.Convert(obj, fi.DeclaringType!), fi),
+ Expression.Convert(val, fi.FieldType)),
+ obj, val).Compile();
+ }
+
+ lock (_cacheLock)
+ {
+ if (!_fieldSetterDict.ContainsKey(fi))
+ {
+ var next = new Dictionary<FieldInfo, Action<Object?, Object?>?>(_fieldSetterDict) { [fi] = setter };
+ _fieldSetterDict = next;
+ }
+ }
+ return setter;
+ }
#endregion
#region 对象拷贝
diff --git a/NewLife.Core/Reflection/Reflect.cs b/NewLife.Core/Reflection/Reflect.cs
index aa026f5..83b7fd3 100644
--- a/NewLife.Core/Reflection/Reflect.cs
+++ b/NewLife.Core/Reflection/Reflect.cs
@@ -11,10 +11,45 @@ namespace NewLife.Reflection;
public static class Reflect
{
#region 静态
+ private static IReflect _provider;
+ // 缓存 Provider 的具体 DefaultReflect 引用,供扩展方法直接调用非虚核心方法,绕过接口分派
+ private static volatile DefaultReflect? _directProvider;
+
+ // 线程本地单态内联缓存:对同一成员的连续调用仅需指针比较(~0.3 ns),跳过字典查找(~3 ns)
+ // [ThreadStatic] 字段在每个线程上独立为 null,无需初始化,无需同步
+ [ThreadStatic] private static PropertyInfo? _tlPropGetInfo;
+ [ThreadStatic] private static Func<Object?, Object?>? _tlPropGetGetter;
+ [ThreadStatic] private static FieldInfo? _tlFieldGetInfo;
+ [ThreadStatic] private static Func<Object?, Object?>? _tlFieldGetGetter;
+ [ThreadStatic] private static PropertyInfo? _tlPropSetInfo;
+ [ThreadStatic] private static Action<Object?, Object?>? _tlPropSetter;
+ [ThreadStatic] private static FieldInfo? _tlFieldSetInfo;
+ [ThreadStatic] private static Action<Object?, Object?>? _tlFieldSetter;
+ [ThreadStatic] private static MethodInfo? _tlInvoke0Mi;
+ [ThreadStatic] private static Func<Object?, Object?>? _tlInvoker0;
+ [ThreadStatic] private static MethodInfo? _tlInvokeNMi;
+ [ThreadStatic] private static Func<Object?, Object?[]?, Object?>? _tlInvokerN;
+ [ThreadStatic] private static Type? _tlFactoryType;
+ [ThreadStatic] private static Func<Object>? _tlFactory;
+
/// <summary>当前反射提供者</summary>
- public static IReflect Provider { get; set; }
+ public static IReflect Provider
+ {
+ get => _provider;
+ set
+ {
+ _provider = value;
+ // 仅当 Provider 是精确的 DefaultReflect 实例(非子类)时才走直达内部路径,避免绕过子类重写
+ _directProvider = value?.GetType() == typeof(DefaultReflect) ? (DefaultReflect)value : null;
+ }
+ }
- static Reflect() => Provider = new DefaultReflect();// 如果需要使用快速反射,启用下面这一行//Provider = new EmitReflect();
+ static Reflect()
+ {
+ Provider = new DefaultReflect();
+ // 如果需要使用快速反射,启用下面这一行
+ //Provider = new EmitReflect();
+ }
#endregion
#region 反射获取
@@ -135,7 +170,22 @@ public static class Reflect
{
if (type == null) throw new ArgumentNullException(nameof(type));
- return Provider.CreateInstance(type, parameters);
+ // P2:单态内联缓存,同一类型连续创建直接取委托,绕过字典查找 (~3 ns)
+ if (parameters == null || parameters.Length == 0)
+ {
+ if (_tlFactoryType == type)
+ return _tlFactory != null ? _tlFactory() : Activator.CreateInstance(type, true);
+
+ var dict = DefaultReflect._instanceFactoryDict;
+ if (dict.TryGetValue(type, out var factory))
+ {
+ _tlFactoryType = type;
+ _tlFactory = factory;
+ return factory != null ? factory() : Activator.CreateInstance(type, true);
+ }
+ }
+ var dp = _directProvider;
+ return dp != null ? dp.CreateInstanceCore(type, parameters) : Provider.CreateInstance(type, parameters);
}
/// <summary>反射调用指定对象的方法。target为类型时调用其静态方法</summary>
@@ -193,7 +243,46 @@ public static class Reflect
if (method == null) throw new ArgumentNullException(nameof(method));
if (!method.IsStatic && target == null) throw new ArgumentNullException(nameof(target));
- return Provider.Invoke(target, method, parameters);
+ // P2:单态内联缓存,同一方法连续调用绕过字典查找 (~3 ns → ~0.3 ns)
+ if (method is MethodInfo mi)
+ {
+ if (parameters == null || parameters.Length == 0)
+ {
+ if (_tlInvoke0Mi == mi)
+ return _tlInvoker0 != null ? _tlInvoker0(target) : method.Invoke(target, null);
+
+ Func<Object?, Object?>? inv0;
+ var dict0 = DefaultReflect._invoker0Dict;
+ if (!dict0.TryGetValue(mi, out inv0))
+ {
+ var dp0 = _directProvider;
+ if (dp0 == null) return Provider.Invoke(target, method, parameters);
+ inv0 = dp0.AddInvoker0(mi);
+ }
+ _tlInvoke0Mi = mi;
+ _tlInvoker0 = inv0;
+ return inv0 != null ? inv0(target) : method.Invoke(target, null);
+ }
+ else
+ {
+ if (_tlInvokeNMi == mi)
+ return _tlInvokerN != null ? _tlInvokerN(target, parameters) : method.Invoke(target, parameters);
+
+ Func<Object?, Object?[]?, Object?>? invN;
+ var dictN = DefaultReflect._invokerNDict;
+ if (!dictN.TryGetValue(mi, out invN))
+ {
+ var dpN = _directProvider;
+ if (dpN == null) return Provider.Invoke(target, method, parameters);
+ invN = dpN.AddInvokerN(mi);
+ }
+ _tlInvokeNMi = mi;
+ _tlInvokerN = invN;
+ return invN != null ? invN(target, parameters) : method.Invoke(target, parameters);
+ }
+ }
+ var dpFallback = _directProvider;
+ return dpFallback != null ? dpFallback.InvokeCore(target, method, parameters) : Provider.Invoke(target, method, parameters);
}
/// <summary>反射调用指定对象的方法</summary>
@@ -267,12 +356,42 @@ public static class Reflect
//if (target is IModel model && member is PropertyInfo) return model[member.Name];
+ // P2:单态内联缓存,同一成员连续访问绕过字典查找 (~3 ns → ~0.3 ns)
if (member is PropertyInfo property)
- return Provider.GetValue(target, property);
+ {
+ if (_tlPropGetInfo == property)
+ return _tlPropGetGetter != null ? _tlPropGetGetter(target) : property.GetValue(target, null);
+
+ Func<Object?, Object?>? getter;
+ var dict = DefaultReflect._propGetterDict;
+ if (!dict.TryGetValue(property, out getter))
+ {
+ var dp = _directProvider;
+ if (dp == null) return Provider.GetValue(target, property);
+ getter = dp.AddPropGetter(property);
+ }
+ _tlPropGetInfo = property;
+ _tlPropGetGetter = getter;
+ return getter != null ? getter(target) : property.GetValue(target, null);
+ }
else if (member is FieldInfo field)
- return Provider.GetValue(target, field);
- else
- throw new ArgumentOutOfRangeException(nameof(member));
+ {
+ if (_tlFieldGetInfo == field)
+ return _tlFieldGetGetter != null ? _tlFieldGetGetter(target) : field.GetValue(target);
+
+ Func<Object?, Object?>? getter;
+ var dict = DefaultReflect._fieldGetterDict;
+ if (!dict.TryGetValue(field, out getter))
+ {
+ var dp = _directProvider;
+ if (dp == null) return Provider.GetValue(target, field);
+ getter = dp.AddFieldGetter(field);
+ }
+ _tlFieldGetInfo = field;
+ _tlFieldGetGetter = getter;
+ return getter != null ? getter(target) : field.GetValue(target);
+ }
+ throw new ArgumentOutOfRangeException(nameof(member));
}
/// <summary>设置目标对象指定名称的属性/字段值,若不存在返回false</summary>
@@ -313,11 +432,62 @@ public static class Reflect
//// 借助 IModel 优化取值赋值,有 IExtend 扩展属性的实体类过于复杂而不支持,例如IEntity就有脏数据问题
//if (target is IModel model && target is not IExtend && member is PropertyInfo)
// model[member.Name] = value;
- //else
+ //else
+ // P2:单态内联缓存 + ChangeType 快路径,同一成员连续写绕过字典查找
if (member is PropertyInfo pi)
- Provider.SetValue(target, pi, value);
+ {
+ if (_tlPropSetInfo == pi)
+ {
+ var pt = pi.PropertyType;
+ var converted = value == null || value.GetType() == pt ? value : value.ChangeType(pt);
+ if (_tlPropSetter != null) _tlPropSetter(target, converted);
+ else pi.SetValue(target, converted, null);
+ return;
+ }
+ Action<Object?, Object?>? setter;
+ var dict = DefaultReflect._propSetterDict;
+ if (!dict.TryGetValue(pi, out setter))
+ {
+ var dp = _directProvider;
+ if (dp == null) { Provider.SetValue(target, pi, value); return; }
+ setter = dp.AddPropSetter(pi);
+ }
+ _tlPropSetInfo = pi;
+ _tlPropSetter = setter;
+ {
+ var pt = pi.PropertyType;
+ var converted = value == null || value.GetType() == pt ? value : value.ChangeType(pt);
+ if (setter != null) setter(target, converted);
+ else pi.SetValue(target, converted, null);
+ }
+ }
else if (member is FieldInfo fi)
- Provider.SetValue(target, fi, value);
+ {
+ if (_tlFieldSetInfo == fi)
+ {
+ var ft = fi.FieldType;
+ var converted = value == null || value.GetType() == ft ? value : value.ChangeType(ft);
+ if (_tlFieldSetter != null) _tlFieldSetter(target, converted);
+ else fi.SetValue(target, converted);
+ return;
+ }
+ Action<Object?, Object?>? setter;
+ var dict = DefaultReflect._fieldSetterDict;
+ if (!dict.TryGetValue(fi, out setter))
+ {
+ var dp = _directProvider;
+ if (dp == null) { Provider.SetValue(target, fi, value); return; }
+ setter = dp.AddFieldSetter(fi);
+ }
+ _tlFieldSetInfo = fi;
+ _tlFieldSetter = setter;
+ {
+ var ft = fi.FieldType;
+ var converted = value == null || value.GetType() == ft ? value : value.ChangeType(ft);
+ if (setter != null) setter(target, converted);
+ else fi.SetValue(target, converted);
+ }
+ }
else
throw new ArgumentOutOfRangeException(nameof(member));
}