来源:https://www.cnblogs.com/lxhbky/p/12219080.html
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace StockCheckApp.Utils
{
    public sealed class CsvHelper
    {
        private static readonly CsvHelper instance = new CsvHelper();
        public static CsvHelper getInstance()
        {
            return instance;
        }

        /// <summary>
        /// 日志
        /// </summary>
        //private ILogger _Logger { get; set; }
        //public CsvHelper(ILogger<CsvHelper> logger)
        //{
        //    this._Logger = logger;
        //}
        private CsvHelper() { }

        public List<T> Read<T>(string filePath, CsvFileDescription fileDescription) where T : class, new()
        {
            List<T> tList = new List<T>(50 * 10000);

            T t = null;
            int currentRawIndex = 0;

            if (File.Exists(filePath))
            {
                using (StreamReader streamReader = new StreamReader(filePath, fileDescription.Encoding))
                {
                    Dictionary<int, FieldMapper> fieldMapperDic = FieldMapper.GetModelFieldMapper<T>().ToDictionary(m => m.CSVTitleIndex);
                    string rawValue = null;
                    string[] rawValueArray = null;
                    PropertyInfo propertyInfo = null;
                    string propertyValue = null;
                    bool rawReadEnd = false;

                    bool isExistSplitChart = false;
                    do
                    {
                        rawValue = streamReader.ReadLine();

                        //标题行
                        if (currentRawIndex > fileDescription.TitleRawIndex)
                        {
                            if (!string.IsNullOrEmpty(rawValue))
                            {
                                //替换字符串含有分隔符为{分隔符},最后再替换回来
                                if (rawValue.Contains("\""))
                                {
                                    isExistSplitChart = true;

                                    int yhBeginIndex = 0;
                                    int yhEndIndex = 0;
                                    string yhText = null;
                                    do
                                    {
                                        yhBeginIndex = StringHelper.GetIndexOfStr(rawValue, "\"", 1);
                                        yhEndIndex = StringHelper.GetIndexOfStr(rawValue, "\"", 2);
                                        yhText = rawValue.Substring(yhBeginIndex, (yhEndIndex - yhBeginIndex + 1));
                                        string newYHText = yhText.Replace("\"", "").Replace(fileDescription.SeparatorChar.ToString(), "{分隔符}");
                                        rawValue = rawValue.Replace(yhText, newYHText);
                                    } while (rawValue.Contains("\""));
                                }

                                rawValueArray = rawValue.Split(fileDescription.SeparatorChar);

                                t = new T();
                                foreach (var fieldMapper in fieldMapperDic)
                                {
                                    propertyInfo = fieldMapper.Value.PropertyInfo;
                                    propertyValue = rawValueArray[fieldMapper.Key];
                                    if (!string.IsNullOrEmpty(propertyValue))
                                    {
                                        try
                                        {
                                            if (isExistSplitChart && propertyValue.Contains("{分隔符}"))
                                            {
                                                propertyValue = propertyValue.Replace("{分隔符}", fileDescription.SeparatorChar.ToString());
                                            }

                                            TypeHelper.SetPropertyValue(t, propertyInfo.Name, propertyValue);
                                        }
                                        catch (Exception e)
                                        {
                                            string msg = $"第{currentRawIndex + 1}行数据{propertyValue}转换属性{propertyInfo.Name}-{propertyInfo.PropertyType.Name}失败!";
                                            //this._Logger.LogWarning(e, msg);
                                            //continue;
                                            throw new Exception(msg);
                                        }
                                    }
                                }
                                tList.Add(t);
                            }
                            else
                            {
                                rawReadEnd = true;
                            }
                        }
                        currentRawIndex++;
                    } while (rawReadEnd == false);
                }
            }


            return tList;
        }

        public void WriteFile<T>(string path, List<T> tList, CsvFileDescription fileDescription) where T : class, new()
        {
            if (!string.IsNullOrEmpty(path))
            {
                string fileDirectoryPath = null;
                if (path.Contains("\\"))
                {
                    fileDirectoryPath = path.Substring(0, path.LastIndexOf('\\'));
                }
                else
                {
                    fileDirectoryPath = path.Substring(0, path.LastIndexOf('/'));
                }
                if (!Directory.Exists(fileDirectoryPath))
                {
                    Directory.CreateDirectory(fileDirectoryPath);
                }

                int dataCount = tList.Count;
                Dictionary<int, FieldMapper> fieldMapperDic = FieldMapper.GetModelFieldMapper<T>().ToDictionary(m => m.CSVTitleIndex);
                int titleCount = fieldMapperDic.Keys.Count;//.Max();
                string[] rawValueArray = new string[titleCount];
                StringBuilder rawValueBuilder = new StringBuilder();
                string rawValue = null;
                T t = null;
                PropertyInfo propertyInfo = null;
                int currentRawIndex = 0;
                int tIndex = 0;

                using (StreamWriter streamWriter = new StreamWriter(path, false, fileDescription.Encoding))
                {
                    do
                    {
                        try
                        {
                            rawValue = "";

#if DEBUG
                            if (currentRawIndex % 10000 == 0)
                            {
                                string msg = $"已写入文件:{path},数据量:{currentRawIndex}";
                                //this._Logger.LogInformation(msg);
                            }
#endif

                            if (currentRawIndex >= fileDescription.TitleRawIndex)
                            {
                                //清空数组数据
                                for (int i = 0; i < titleCount; i++)
                                {
                                    rawValueArray[i] = "";
                                }

                                if (currentRawIndex > fileDescription.TitleRawIndex)
                                {
                                    t = tList[tIndex];
                                    tIndex++;
                                }
                                foreach (var fieldMapperItem in fieldMapperDic)
                                {
                                    //写入标题行
                                    if (currentRawIndex == fileDescription.TitleRawIndex)
                                    {
                                        rawValueArray[fieldMapperItem.Key] = fieldMapperItem.Value.CSVTitle;
                                    }
                                    //真正的数据从标题行下一行开始写
                                    else
                                    {
                                        propertyInfo = fieldMapperItem.Value.PropertyInfo;
                                        object propertyValue = propertyInfo.GetValue(t);
                                        string formatValue = null;
                                        if (propertyValue != null)
                                        {
                                            if (propertyInfo.PropertyType is IFormattable && !string.IsNullOrEmpty(fieldMapperItem.Value.OutputFormat))
                                            {
                                                formatValue = ((IFormattable)propertyValue).ToString(fieldMapperItem.Value.OutputFormat, null);
                                            }
                                            else
                                            {
                                                formatValue = propertyValue.ToString();
                                            }

                                            //如果属性值含有分隔符,则使用双引号包裹
                                            if (formatValue.Contains(fileDescription.SeparatorChar.ToString()))
                                            {
                                                formatValue = $"\"{formatValue}\"";
                                            }
                                            rawValueArray[fieldMapperItem.Key] = formatValue;
                                        }
                                    }
                                }
                                rawValue = string.Join(fileDescription.SeparatorChar, rawValueArray);
                            }
                            rawValueBuilder.Append(rawValue + "\r\n");
                        }
                        catch (Exception e)
                        {
                            string msg = $"(异常)Excel第{currentRawIndex + 1}行,数据列表第{tIndex + 1}个数据写入失败!rawValue:{rawValue}";
                            //this._Logger.LogWarning(e, msg);
                            throw new Exception(msg);
                        }

                        currentRawIndex++;
                    } while (tIndex < dataCount);
                    streamWriter.Write(rawValueBuilder.ToString());

                    streamWriter.Close();
                    streamWriter.Dispose();
                }
            }
        }

    }
}

  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace StockCheckApp.Utils
{
    /// <summary>
    /// 字段映射类
    /// </summary>
    public class FieldMapper
    {
        /// <summary>
        /// 属性信息
        /// </summary>
        public PropertyInfo PropertyInfo { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        public string CSVTitle { get; set; }
        /// <summary>
        /// 标题下标位置
        /// </summary>
        public int CSVTitleIndex { get; set; }
        /// <summary>
        /// 字符输出格式(数字和日期类型需要)
        /// </summary>
        public string OutputFormat { get; set; }

        public static List<FieldMapper> GetModelFieldMapper<T>()
        {
            List<FieldMapper> fieldMapperList = new List<FieldMapper>(100);

            List<PropertyInfo> tPropertyInfoList = typeof(T).GetProperties().ToList();
            CsvColumnAttribute csvColumnAttribute = null;
            foreach (var tPropertyInfo in tPropertyInfoList)
            {
                csvColumnAttribute = (CsvColumnAttribute)tPropertyInfo.GetCustomAttribute(typeof(CsvColumnAttribute));
                if (csvColumnAttribute != null)
                {
                    fieldMapperList.Add(new FieldMapper
                    {
                        PropertyInfo = tPropertyInfo,
                        CSVTitle = csvColumnAttribute.Title,
                        CSVTitleIndex = csvColumnAttribute.TitleIndex,
                        OutputFormat = csvColumnAttribute.OutputFormat
                    });
                }
            }
            return fieldMapperList;
        }

    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace StockCheckApp.Utils
{
    public class StringHelper
    {
        /// <summary>
        /// 获取字符串中第strPosition个位置的str的下标
        /// </summary>
        /// <param name="text"></param>
        /// <param name="str"></param>
        /// <param name="strPosition"></param>
        /// <returns></returns>
        public static int GetIndexOfStr(string text, string str, int strPosition)
        {
            int strIndex = -1;

            int currentPosition = 0;
            if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(str) && strPosition >= 1)
            {
                do
                {
                    currentPosition++;
                    if (strIndex == -1)
                    {
                        strIndex = text.IndexOf(str);
                    }
                    else
                    {
                        strIndex = text.IndexOf(str, strIndex + 1);
                    }
                } while (currentPosition < strPosition);
            }

            return strIndex;
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace StockCheckApp.Utils
{
    /// <summary>
    /// 类型帮助类
    /// </summary>
    public class TypeHelper
    {
        private static Dictionary<Type, List<PropertyInfo>> _TypePropertyDic = new Dictionary<Type, List<PropertyInfo>>(0);

        /// <summary>
        /// 获取T属性列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<PropertyInfo> GetTPropertyDic<T>()
        {
            Type tType = typeof(T);
            List<PropertyInfo> propertyInfoList = null;
            if (TypeHelper._TypePropertyDic.ContainsKey(tType))
            {
                propertyInfoList = TypeHelper._TypePropertyDic[tType];
            }
            else
            {
                propertyInfoList = tType.GetProperties().ToList();
                TypeHelper._TypePropertyDic.Add(tType, propertyInfoList);
            }

            return propertyInfoList;
        }

        /// <summary>
        /// 获取t属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetPropertyValue<T>(T t, string propertyName)
        {
            object value = null;

            Type tType = typeof(T);
            List<PropertyInfo> propertyInfoList = TypeHelper.GetTPropertyDic<T>();

            PropertyInfo propertyInfo = propertyInfoList.FirstOrDefault(m => m.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));

            if (propertyInfo != null)
            {
                value = propertyInfo.GetValue(t);
            }
            return value;
        }

        /// <summary>
        /// 设置t属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="propertyName"></param>
        /// <param name="propertyValue"></param>
        public static void SetPropertyValue<T>(T t, string propertyName, object propertyValue)
        {
            Type tType = typeof(T);
            List<PropertyInfo> propertyInfoList = TypeHelper.GetTPropertyDic<T>();

            PropertyInfo propertyInfo = propertyInfoList.FirstOrDefault(m => m.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));

            if (propertyInfo != null && propertyValue != null)
            {
                if (!propertyInfo.PropertyType.IsGenericType)
                {
                    propertyInfo.SetValue(t, Convert.ChangeType(propertyValue, propertyInfo.PropertyType));
                }
                else
                {
                    Type genericTypeDefinition = propertyInfo.PropertyType.GetGenericTypeDefinition();
                    if (genericTypeDefinition == typeof(Nullable<>))
                    {
                        propertyInfo.SetValue(t, Convert.ChangeType(propertyValue, Nullable.GetUnderlyingType(propertyInfo.PropertyType)));
                    }
                }
            }
        }

        /// <summary>
        /// 克隆相同属性数据到另一个类列表中
        /// </summary>
        /// <typeparam name="Tin"></typeparam>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="inList"></param>
        /// <returns></returns>
        public static List<Tout> CloneData<Tin, Tout>(List<Tin> inList) where Tout : new()
        {
            List<Tout> outList = new List<Tout>(0);

            if (inList != null && inList.Count > 0)
            {
                Dictionary<string, PropertyInfo> inTProList = TypeHelper.GetTPropertyDic<Tin>().ToDictionary(m => m.Name);
                Dictionary<string, PropertyInfo> outTProList = TypeHelper.GetTPropertyDic<Tout>().ToDictionary(m => m.Name);

                Tout outT = default(Tout);
                foreach (var item in inList)
                {
                    outT = new Tout();
                    foreach (var inProItem in inTProList)
                    {
                        if (outTProList.ContainsKey(inProItem.Key))
                        {
                            outTProList[inProItem.Key].SetValue(outT, inProItem.Value.GetValue(item));
                        }
                    }
                    outList.Add(outT);
                }
            }

            return outList;
        }

    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace StockCheckApp.Utils
{
    /// <summary>
    /// Csv文件类特性标记
    /// </summary>
    [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = false)]
    public class CsvColumnAttribute : System.Attribute
    {
        internal const int defaultTitleIndex = Int32.MaxValue;
        /// <summary>
        /// 标题
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// 标题位置(从0开始)
        /// </summary>
        public int TitleIndex { get; set; }
        /// <summary>
        /// 字符输出格式(数字和日期类型需要)
        /// </summary>
        public string OutputFormat { get; set; }

        public CsvColumnAttribute()
        {
            Title = "";
            TitleIndex = defaultTitleIndex;
            OutputFormat = "";
        }

        public CsvColumnAttribute(string title, int titleIndex, string outputFormat)
        {
            Title = title;
            TitleIndex = titleIndex;
            OutputFormat = outputFormat;
        }
    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace StockCheckApp.Utils
{
    public class CsvFileDescription
    {
        public CsvFileDescription() : this(0)
        {
        }
        public CsvFileDescription(int titleRawIndex) : this(',', titleRawIndex, Encoding.UTF8)
        {
        }
        public CsvFileDescription(char separatorChar, int titleRawIndex, Encoding encoding)
        {
            this.SeparatorChar = separatorChar;
            this.TitleRawIndex = titleRawIndex;
            this.Encoding = encoding;
        }

        /// <summary>
        /// CSV文件字符编码
        /// </summary>
        public Encoding Encoding { get; set; }

        /// <summary>
        /// 分隔符(默认为(,),也可以是其他分隔符如(\t))
        /// </summary>
        public char SeparatorChar { get; set; }
        /// <summary>
        /// 标题所在行位置(默认为0,没有标题填-1)
        /// </summary>
        public int TitleRawIndex { get; set; }

    }
}

  

using StockCheckApp.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;

namespace StockCheckApp.Models
{
    public class GoodsCheckInfo
    {

        /// <summary>
        /// 指示当前对象自创建以来,属性 GoodsCode 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isGoodsCodeSetValue;

        private string _goodsCode;

        /// <summary>
        /// 商品代码
        /// </summary>
        [CsvColumn(Title = "商品代码", TitleIndex = 0, OutputFormat = "")]
        public string GoodsCode
        {
            get
            {
                return this._goodsCode;
            }
            set
            {
                this._goodsCode = value;
                this._isGoodsCodeSetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 LotNo 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isLotNoSetValue;

        private string _lotNo;

        /// <summary>
        /// 批号
        /// </summary>
        [CsvColumn(Title = "批号", TitleIndex = 1, OutputFormat = "")]
        public string LotNo
        {
            get
            {
                return this._lotNo;
            }
            set
            {
                this._lotNo = value;
                this._isLotNoSetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 GoodsQty 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isGoodsQtySetValue;

        private string _goodsQty;

        /// <summary>
        /// 盘点数量
        /// </summary>
        [CsvColumn(Title = "盘点数量", TitleIndex = 2, OutputFormat = "")]
        public string GoodsQty
        {
            get
            {
                return this._goodsQty;
            }
            set
            {
                this._goodsQty = value;
                this._isGoodsQtySetValue = true;
            }
        }

        public bool UpdateTag { get; set; }
    }
}

using StockCheckApp.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;

namespace StockCheckApp.Models
{
    public class GoodsInfo
    {

        /// <summary>
        /// 指示当前对象自创建以来,属性 GoodsCode 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isGoodsCodeSetValue;

        private string _goodsCode;

        /// <summary>
        /// 商品编号
        /// </summary>
        [CsvColumn(Title = "商品代码", TitleIndex = 0, OutputFormat = "")]
        public string GoodsCode
        {
            get
            {
                return this._goodsCode;
            }
            set
            {
                this._goodsCode = value;
                this._isGoodsCodeSetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 BarCode1 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isBarCode1SetValue;

        private string _barCode1;

        /// <summary>
        /// 商品条码1
        /// </summary>
        [CsvColumn(Title = "条码1", TitleIndex = 1, OutputFormat = "")]
        public string BarCode1
        {
            get
            {
                return this._barCode1;
            }
            set
            {
                this._barCode1 = value;
                this._isBarCode1SetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 BarCode2 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isBarCode2SetValue;

        private string _barCode2;

        /// <summary>
        /// 商品条码2
        /// </summary>
        [CsvColumn(Title = "条码2", TitleIndex = 2, OutputFormat = "")]
        public string BarCode2
        {
            get
            {
                return this._barCode2;
            }
            set
            {
                this._barCode2 = value;
                this._isBarCode2SetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 BarCode3 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isBarCode3SetValue;

        private string _barCode3;

        /// <summary>
        /// 商品条码3
        /// </summary>
        [CsvColumn(Title = "条码3", TitleIndex = 3, OutputFormat = "")]
        public string BarCode3
        {
            get
            {
                return this._barCode3;
            }
            set
            {
                this._barCode3 = value;
                this._isBarCode3SetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 BarCode4 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isBarCode4SetValue;

        private string _barCode4;

        /// <summary>
        /// 商品条码4
        /// </summary>
        [CsvColumn(Title = "条码4", TitleIndex = 4, OutputFormat = "")]
        public string BarCode4
        {
            get
            {
                return this._barCode4;
            }
            set
            {
                this._barCode4 = value;
                this._isBarCode4SetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 BarCode5 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isBarCode5SetValue;

        private string _barCode5;

        /// <summary>
        /// 商品条码5
        /// </summary>
        [CsvColumn(Title = "条码5", TitleIndex = 5, OutputFormat = "")]
        public string BarCode5
        {
            get
            {
                return this._barCode5;
            }
            set
            {
                this._barCode5 = value;
                this._isBarCode5SetValue = true;
            }
        }

        /// <summary>
        /// 指示当前对象自创建以来,属性 GoodsName 是否已经设置了值(含设置为 null)。
        /// </summary>
        protected bool _isGoodsNameSetValue;

        private string _goodsName;

        /// <summary>
        /// 商品名称(中文)
        /// </summary>
        [CsvColumn(Title = "商品名称", TitleIndex = 6, OutputFormat = "")]
        public string GoodsName
        {
            get
            {
                return this._goodsName;
            }
            set
            {
                this._goodsName = value;
                this._isGoodsNameSetValue = true;
            }
        }
    }
}

使用:
string dirGoodsMst = Directory.GetCurrentDirectory() + "\\DataResource\\GoodsMst.csv";
List<GoodsInfo> GoodsInfos = CsvHelper.getInstance().Read<GoodsInfo>(dirGoodsMst, csvFileDescription);

/// <summary>
/// 反序列化固定字符串格式 属性用\t间隔,行用\n间隔
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
public static List<T> DeserializeFromString<T>(string data, bool exceptHeader)
{
    //类型T的所有属性
    Dictionary<int, FieldMapper> fieldMapperDic = FieldMapper.GetModelFieldMapper<T>().ToDictionary(m => m.ColumnIndex);

    List<T> list = new();
    var targetType = typeof(T);

    var dataString = data.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
    if (exceptHeader && dataString.Length > 0)
    {
        dataString = dataString.Remove(dataString[0]);
    }
    foreach (var item in dataString)
    {
        //创建新对象
        T t = (T)Activator.CreateInstance(targetType);
        //对象值列表
        var stockCheckItemStrArray = item.Split(new string[] { "\t" }, StringSplitOptions.None);
        //数据长度和字段长度比对,哪个短,以哪个为准。超出的不予赋值。避免报错。
        int dataCount = stockCheckItemStrArray.Length;
        if (stockCheckItemStrArray.Length > fieldMapperDic.Count)
        {
            //throw new Exception("数据长度" + stockCheckItemStrArray.Length + ",超出字段长度" + fieldMapperDic.Count + ":" + item);
            dataCount = fieldMapperDic.Count;
            string msgWrite = "targetType:" + targetType + ",数据长度" + stockCheckItemStrArray.Length + ",超出字段长度" + fieldMapperDic.Count + "" + item;
            AppTraceLog.WriteInfo(msgWrite);
        }
        //循环为对象属性赋值
        for (int i = 0; i < dataCount; i++)
        {
            string proName = fieldMapperDic[i].PropertyInfo.Name;
            string proValue = stockCheckItemStrArray[i];
            PropertyInfo pit = targetType.GetProperty(proName);
            pit.SetValue(t, proValue, null);
        }
        //保存到集合中
        list.Add(t);
    }
    return list;
}
/// <summary>
/// 反序列化固定字符串格式 属性用\t间隔,行用\n间隔
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
public static List<T> DeserializeFromCompressString<T>(string data, bool exceptHeader)
{
    //解压缩字符串
    string decompressStr = StringCompress.DecompressString(data);
    var res = DeserializeFromString<T>(decompressStr, exceptHeader);
    return res;
}

 

posted on 2022-09-29 15:47  邢帅杰  阅读(39)  评论(0编辑  收藏  举报