From 81d602208d64142957b4638d74fa49c093df6e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <505554090@qq.com> Date: Mon, 19 Jun 2023 09:37:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E5=8F=8D=E5=B0=84=E8=B5=8B=E5=80=BC?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=BA=E8=A1=A8=E8=BE=BE=E5=BC=8F=E6=A0=91?= =?UTF-8?q?=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MiniExcel/Reflection/Member.cs | 15 +++ src/MiniExcel/Reflection/MemberGetter.cs | 66 ++++++++++++ src/MiniExcel/Reflection/MemberSetter.cs | 54 ++++++++++ src/MiniExcel/Reflection/Property.cs | 110 ++++++++++++++++++++ src/MiniExcel/Utils/CustomPropertyHelper.cs | 14 +-- src/MiniExcel/Utils/TypeHelper.cs | 14 +-- 6 files changed, 259 insertions(+), 14 deletions(-) create mode 100644 src/MiniExcel/Reflection/Member.cs create mode 100644 src/MiniExcel/Reflection/MemberGetter.cs create mode 100644 src/MiniExcel/Reflection/MemberSetter.cs create mode 100644 src/MiniExcel/Reflection/Property.cs diff --git a/src/MiniExcel/Reflection/Member.cs b/src/MiniExcel/Reflection/Member.cs new file mode 100644 index 0000000..706101f --- /dev/null +++ b/src/MiniExcel/Reflection/Member.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MiniExcelLibs +{ + /// + /// 用于表达式树的成员 + /// + public abstract class Member + { + } +} diff --git a/src/MiniExcel/Reflection/MemberGetter.cs b/src/MiniExcel/Reflection/MemberGetter.cs new file mode 100644 index 0000000..edfbf2c --- /dev/null +++ b/src/MiniExcel/Reflection/MemberGetter.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace MiniExcelLibs +{ + /// + /// 表示属性的Getter + /// + public class MemberGetter + { + /// + /// get方法委托 + /// + private readonly Func m_getFunc; + + /// + /// 表示属性的Getter + /// + /// 属性 + /// + public MemberGetter(PropertyInfo property) + { + m_getFunc = CreateGetterDelegate(property); + } + + /// + /// 表示类型字段或属性的Getter + /// + /// + public MemberGetter(FieldInfo fieldInfo) + { + m_getFunc = CreateGetterDelegate(fieldInfo); + } + + /// + /// 获取属性的值 + /// + /// 实例 + /// + public object Invoke(object instance) + { + return m_getFunc.Invoke(instance); + } + + private static Func CreateGetterDelegate(PropertyInfo property) + { + var param_instance = Expression.Parameter(typeof(object)); + var body_instance = Expression.Convert(param_instance, property.DeclaringType); + var body_property = Expression.Property(body_instance, property); + var body_return = Expression.Convert(body_property, typeof(object)); + + return Expression.Lambda>(body_return, param_instance).Compile(); + } + + private static Func CreateGetterDelegate(FieldInfo fieldInfo) + { + var param_instance = Expression.Parameter(typeof(object)); + var body_instance = Expression.Convert(param_instance, fieldInfo.DeclaringType); + var body_field = Expression.Field(body_instance, fieldInfo); + var body_return = Expression.Convert(body_field, typeof(object)); + + return Expression.Lambda>(body_return, param_instance).Compile(); + } + } +} \ No newline at end of file diff --git a/src/MiniExcel/Reflection/MemberSetter.cs b/src/MiniExcel/Reflection/MemberSetter.cs new file mode 100644 index 0000000..2a7268b --- /dev/null +++ b/src/MiniExcel/Reflection/MemberSetter.cs @@ -0,0 +1,54 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace MiniExcelLibs +{ + /// + /// 表示属性的设置器 + /// + public class MemberSetter + { + /// + /// set方法委托 + /// + private readonly Action setFunc; + + /// + /// 表示属性的Getter + /// + /// 属性 + /// + public MemberSetter(PropertyInfo property) + { + if (property == null) + { + throw new ArgumentNullException(nameof(property)); + } + setFunc = CreateSetterDelegate(property); + } + + /// + /// 设置属性的值 + /// + /// 实例 + /// 值 + /// + public void Invoke(object instance, object value) + { + setFunc.Invoke(instance, value); + } + + private static Action CreateSetterDelegate(PropertyInfo property) + { + var param_instance = Expression.Parameter(typeof(object)); + var param_value = Expression.Parameter(typeof(object)); + + var body_instance = Expression.Convert(param_instance, property.DeclaringType); + var body_value = Expression.Convert(param_value, property.PropertyType); + var body_call = Expression.Call(body_instance, property.GetSetMethod(true), body_value); + + return Expression.Lambda>(body_call, param_instance, param_value).Compile(); + } + } +} \ No newline at end of file diff --git a/src/MiniExcel/Reflection/Property.cs b/src/MiniExcel/Reflection/Property.cs new file mode 100644 index 0000000..659f9f4 --- /dev/null +++ b/src/MiniExcel/Reflection/Property.cs @@ -0,0 +1,110 @@ + +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Reflection; + +namespace MiniExcelLibs +{ + /// + /// 表示属性 + /// + public class Property: Member + { + /// + /// 类型属性的Setter缓存 + /// + private static readonly ConcurrentDictionary m_cached = new ConcurrentDictionary(); + + /// + /// 获取器 + /// + private readonly MemberGetter m_geter; + + /// + /// 设置器 + /// + private readonly MemberSetter m_seter; + + /// + /// 属性 + /// + /// 属性信息 + public Property(PropertyInfo property) + { + Name = property.Name; + Info = property; + + if (property.CanRead == true) + { + CanRead = true; + m_geter = new MemberGetter(property); + } + if (property.CanWrite == true) + { + CanWrite = true; + m_seter = new MemberSetter(property); + } + } + + /// + /// 是否可以读取 + /// + public bool CanRead { get; private set; } + + /// + /// 是否可以写入 + /// + public bool CanWrite { get; private set; } + + /// + /// 获取属性信息 + /// + public PropertyInfo Info { get; private set; } + + /// + /// 获取属性名称 + /// + public string Name { get; protected set; } + + /// + /// 从类型的属性获取属性 + /// + /// 类型 + /// + public static Property[] GetProperties(Type type) + { + return m_cached.GetOrAdd(type, t => t.GetProperties().Select(p => new Property(p)).ToArray()); + } + + /// + /// 获取属性的值 + /// + /// 实例 + /// + /// + public object GetValue(object instance) + { + if (m_geter == null) + { + throw new NotSupportedException(); + } + return m_geter.Invoke(instance); + } + + /// + /// 设置属性的值 + /// + /// 实例 + /// 值 + /// + public void SetValue(object instance, object value) + { + if (m_seter == null) + { + throw new NotSupportedException($"{Name}不允许赋值"); + } + m_seter.Invoke(instance, value); + } + } +} \ No newline at end of file diff --git a/src/MiniExcel/Utils/CustomPropertyHelper.cs b/src/MiniExcel/Utils/CustomPropertyHelper.cs index 37b286f..0e10486 100644 --- a/src/MiniExcel/Utils/CustomPropertyHelper.cs +++ b/src/MiniExcel/Utils/CustomPropertyHelper.cs @@ -14,7 +14,7 @@ internal class ExcelColumnInfo public int? ExcelColumnIndex { get; set; } public string ExcelColumnName { get; set; } public string[] ExcelColumnAliases { get; set; } - public PropertyInfo Property { get; set; } + public Property Property { get; set; } public Type ExcludeNullableType { get; set; } public bool Nullable { get; internal set; } public string ExcelFormat { get; internal set; } @@ -49,7 +49,7 @@ internal static IDictionary GetEmptyExpandoObject(Dictionary GetSaveAsProperties(this Type type, Configuration configuration) { List props = GetExcelPropertyInfo(type, BindingFlags.Public | BindingFlags.Instance, configuration) - .Where(prop => prop.Property.GetGetMethod() != null) + .Where(prop => prop.Property.CanRead) .ToList() /*ignore without set*/; if (props.Count == 0) @@ -103,9 +103,9 @@ internal static List SortCustomProps(List prop internal static List GetExcelCustomPropertyInfos(Type type, string[] keys, Configuration configuration) { List props = GetExcelPropertyInfo(type, BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, configuration) - .Where(prop => prop.Property.GetSetMethod() != null - && !prop.Property.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore) - && !prop.Property.GetAttributeValue((ExcelColumnAttribute x) => x.Ignore)) + .Where(prop => prop.Property.CanWrite + && !prop.Property.Info.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore) + && !prop.Property.Info.GetAttributeValue((ExcelColumnAttribute x) => x.Ignore)) .ToList() /*ignore without set*/; if (props.Count == 0) @@ -124,7 +124,7 @@ internal static List GetExcelCustomPropertyInfos(Type type, str if (p.ExcelColumnIndex > maxIndex) throw new ArgumentException($"ExcelColumnIndex {p.ExcelColumnIndex} over haeder max index {maxkey}"); if (p.ExcelColumnName == null) - throw new InvalidOperationException($"{p.Property.DeclaringType.Name} {p.Property.Name}'s ExcelColumnIndex {p.ExcelColumnIndex} can't find excel column name"); + throw new InvalidOperationException($"{p.Property.Info.DeclaringType.Name} {p.Property.Name}'s ExcelColumnIndex {p.ExcelColumnIndex} can't find excel column name"); } } } @@ -172,7 +172,7 @@ private static IEnumerable ConvertToExcelCustomPropertyInfo(Pro var excelColumnIndex = excelColumn?.Index > -1 ? excelColumn.Index : (int?)null; return new ExcelColumnInfo { - Property = p, + Property = new Property(p), ExcludeNullableType = excludeNullableType, Nullable = gt != null, ExcelColumnAliases = excelColumnName?.Aliases ?? excelColumn?.Aliases, diff --git a/src/MiniExcel/Utils/TypeHelper.cs b/src/MiniExcel/Utils/TypeHelper.cs index 5274cd6..ba1fff0 100644 --- a/src/MiniExcel/Utils/TypeHelper.cs +++ b/src/MiniExcel/Utils/TypeHelper.cs @@ -70,7 +70,7 @@ public static bool IsNumericType(Type type, bool isNullableUnderlyingType = fals var columnName = pInfo.ExcelColumnName ?? pInfo.Property.Name; var startRowIndex = ReferenceHelper.ConvertCellToXY(startCell).Item2; var errorRow = startRowIndex + rowIndex + 1; - throw new ExcelInvalidCastException(columnName, errorRow, itemValue, pInfo.Property.PropertyType, $"ColumnName : {columnName}, CellRow : {errorRow}, Value : {itemValue}, it can't cast to {pInfo.Property.PropertyType.Name} type."); + throw new ExcelInvalidCastException(columnName, errorRow, itemValue, pInfo.Property.Info.PropertyType, $"ColumnName : {columnName}, CellRow : {errorRow}, Value : {itemValue}, it can't cast to {pInfo.Property.Info.PropertyType.Name} type."); } } @@ -108,7 +108,7 @@ public static bool IsNumericType(Type type, bool isNullableUnderlyingType = fals var vs = itemValue?.ToString(); if (pInfo.ExcelFormat != null) { - if (pInfo.Property.PropertyType == typeof(DateTimeOffset) && DateTimeOffset.TryParseExact(vs, pInfo.ExcelFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v2)) + if (pInfo.Property.Info.PropertyType == typeof(DateTimeOffset) && DateTimeOffset.TryParseExact(vs, pInfo.ExcelFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v2)) { newValue = _v2; } @@ -136,17 +136,17 @@ public static bool IsNumericType(Type type, bool isNullableUnderlyingType = fals else newValue = bool.Parse(vs); } - else if (pInfo.Property.PropertyType == typeof(string)) + else if (pInfo.Property.Info.PropertyType == typeof(string)) { newValue = XmlEncoder.DecodeString(itemValue?.ToString()); } - else if (pInfo.Property.PropertyType.IsEnum) + else if (pInfo.Property.Info.PropertyType.IsEnum) { - var fieldInfo = pInfo.Property.PropertyType.GetFields().FirstOrDefault(e => e.GetCustomAttribute(false)?.Description == itemValue?.ToString()); + var fieldInfo = pInfo.Property.Info.PropertyType.GetFields().FirstOrDefault(e => e.GetCustomAttribute(false)?.Description == itemValue?.ToString()); if (fieldInfo != null) - newValue = Enum.Parse(pInfo.Property.PropertyType, fieldInfo.Name, true); + newValue = Enum.Parse(pInfo.Property.Info.PropertyType, fieldInfo.Name, true); else - newValue = Enum.Parse(pInfo.Property.PropertyType, itemValue?.ToString(), true); + newValue = Enum.Parse(pInfo.Property.Info.PropertyType, itemValue?.ToString(), true); } else { -- Gitee