using System; using System.Collections; using System.Linq.Expressions; using System.Reflection; namespace SKIT.FlurlHttpClient.Wechat.TenpayV2.Utilities { internal static class ReflectionHelper { private readonly static Hashtable _ctorCache = new Hashtable(capacity: 128); private readonly static Hashtable _getterCache = new Hashtable(capacity: 128); private readonly static Hashtable _setterCache = new Hashtable(capacity: 128); public static T CreateInstance() where T : new() { // 提供比 new T() 或 Activator.CreateInstance() 更快的无参实例化方法 // 只可针对热点类型使用,否则可能会更慢 Type type = typeof(T); Func? ctor = _ctorCache[type] as Func; if (ctor is null) { ctor = Expression.Lambda>(Expression.New(typeof(T))).Compile(); _ctorCache[type] = ctor; } return ctor.Invoke(); } public static T? GetPropertyValue(object targetObj, PropertyInfo property) { // 提供比 PropertyInfo.GetValue() 更快的属性取值方法 // 只可针对热点类型使用,否则可能会更慢 if (targetObj is null) throw new ArgumentNullException(nameof(targetObj)); if (property is null) throw new ArgumentNullException(nameof(property)); if (!property.CanRead) throw new InvalidOperationException($"Property '{property.Name}' of type '{typeof(T).FullName}' does not have a getter."); Func? getter = _getterCache[property] as Func; if (getter is null) { ParameterExpression targetExpr = Expression.Parameter(typeof(object)); UnaryExpression castTargetExpr = Expression.Convert(targetExpr, targetObj.GetType()); MemberExpression getPropertyValueExpr = Expression.Property(castTargetExpr, property); UnaryExpression castPropertyValueExpr = Expression.Convert(getPropertyValueExpr, typeof(T)); getter = Expression.Lambda>(castPropertyValueExpr, targetExpr).Compile(); _getterCache[property] = getter; } return getter.Invoke(targetObj); } public static void SetPropertyValue(object targetObj, PropertyInfo property, T? value) { // 提供比 PropertyInfo.SetValue() 更快的属性赋值方法 // 只可针对热点类型使用,否则可能会更慢 if (targetObj is null) throw new ArgumentNullException(nameof(targetObj)); if (property is null) throw new ArgumentNullException(nameof(property)); if (!property.CanWrite) throw new InvalidOperationException($"Property '{property.Name}' of type '{typeof(T).FullName}' does not have a setter."); Action? setter = _setterCache[property] as Action; if (setter is null) { ParameterExpression targetExpr = Expression.Parameter(typeof(object)); ParameterExpression propertyValueExpr = Expression.Parameter(typeof(T)); UnaryExpression castTargetExpr = Expression.Convert(targetExpr, targetObj.GetType()); UnaryExpression castPropertyValueExpr = Expression.Convert(propertyValueExpr, property.PropertyType); MethodCallExpression setPropertyValueExpr = Expression.Call(castTargetExpr, property.GetSetMethod()!, castPropertyValueExpr); setter = Expression.Lambda>(setPropertyValueExpr, targetExpr, propertyValueExpr).Compile(); _setterCache[property] = setter; } setter.Invoke(targetObj, value); } public static T? GetElementValue(Array array, int index) { return (T?)array.GetValue(index); } public static void SetElementValue(Array array, int index, T? element) { array.SetValue(element, index); } } }