using Luban.Common.Utils; using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.DataSources.Excel; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Utils; using Luban.Job.Common.Types; using Luban.Job.Common.TypeVisitors; using System; using System.Collections.Generic; using System.Runtime.Serialization; namespace Luban.Job.Cfg.DataCreators { enum EReadPolicy { SKIP_NULL_CELL = 0x1, SKIP_BLANK_CELL = 0x2, NULL_AS_NULL = 0x4, NULL_STR_AS_NULL = 0x8, } class InvalidExcelDataException : Exception { public InvalidExcelDataException() { } public InvalidExcelDataException(string message) : base(message) { } public InvalidExcelDataException(string message, Exception innerException) : base(message, innerException) { } protected InvalidExcelDataException(SerializationInfo info, StreamingContext context) : base(info, context) { } } class ExcelDataCreator : ITypeFuncVisitor { public static ExcelDataCreator Ins { get; } = new ExcelDataCreator(); private bool CheckNull(bool nullable, object o) { if (o is string s && s == "null") { if (nullable) { return true; } else { throw new InvalidExcelDataException($"单元格没有填有效数据"); } } return false; } private static bool CreateBool(object x) { if (x is bool b) { return b; } var s = x.ToString().ToLower().Trim(); switch (s) { case "true": case "是": return true; case "false": case "否": return false; default: throw new InvalidExcelDataException($"{s} 不是 bool 类型的值 (true 或 false)"); } } public DType Accept(TBool type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } return new DBool(CreateBool(d)); } public DType Accept(TByte type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } if (!byte.TryParse(d.ToString(), out byte v)) { throw new InvalidExcelDataException($"{d} 不是 byte 类型值"); } return new DByte(v); } public DType Accept(TShort type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } if (!short.TryParse(d.ToString(), out short v)) { throw new InvalidExcelDataException($"{d} 不是 short 类型值"); } return new DShort(v); } public DType Accept(TFshort type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } if (!short.TryParse(d.ToString(), out short v)) { throw new InvalidExcelDataException($"{d} 不是 short 类型值"); } return new DFshort(v); } public DType Accept(TInt type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } var ds = d.ToString(); if (converter is TEnum te) { if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) { return new DInt(c); } } if (!int.TryParse(ds, out var v)) { throw new InvalidExcelDataException($"{d} 不是 int 类型值"); } return new DInt(v); } public DType Accept(TFint type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } var ds = d.ToString(); if (converter is TEnum te) { if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) { return new DFint(c); } } if (!int.TryParse(ds, out var v)) { throw new InvalidExcelDataException($"{d} 不是 int 类型值"); } return new DFint(v); } public DType Accept(TLong type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } var ds = d.ToString(); if (converter is TEnum te) { if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) { return new DLong(c); } } if (!long.TryParse(ds, out var v)) { throw new InvalidExcelDataException($"{d} 不是 long 类型值"); } return new DLong(v); } public DType Accept(TFlong type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } var ds = d.ToString(); if (converter is TEnum te) { if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) { return new DFlong(c); } } if (!long.TryParse(ds, out var v)) { throw new InvalidExcelDataException($"{d} 不是 long 类型值"); } return new DFlong(v); } public DType Accept(TFloat type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } if (!float.TryParse(d.ToString(), out var v)) { throw new InvalidExcelDataException($"{d} 不是 float 类型值"); } return new DFloat(v); } public DType Accept(TDouble type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } if (!double.TryParse(d.ToString(), out var v)) { throw new InvalidExcelDataException($"{d} 不是 double 类型值"); } return new DDouble(v); } public DType Accept(TEnum type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } return new DEnum(type, d.ToString().Trim()); } public DType Accept(TString type, object converter, ExcelStream x, DefAssembly ass) { if (x.NamedMode && x.IncludeNullAndEmptySize != 1) { throw new InvalidExcelDataException("excel string类型在标题头对应模式下必须正好占据一个单元格"); } return new DString(ParseString(x.Read(x.NamedMode))); } public DType Accept(TBytes type, object converter, ExcelStream x, DefAssembly ass) { throw new NotImplementedException(); } private static string ParseString(object d) { if (d == null) { return ""; } else if (d is string s) { return DataUtil.UnEscapeString(s); } else { return d.ToString(); } } public DType Accept(TText type, object converter, ExcelStream x, DefAssembly ass) { if (x.NamedMode && x.IncludeNullAndEmptySize != 2) { throw new InvalidExcelDataException("excel text 类型在标题头对应模式下必须正好占据2个单元格"); } string key = ParseString(x.Read(x.NamedMode)); string text = ParseString(x.Read(x.NamedMode)); DataUtil.ValidateText(key, text); return new DText(key, text); } private List CreateBeanFields(DefBean bean, ExcelStream stream, DefAssembly ass) { var list = new List(); foreach (DefField f in bean.HierarchyFields) { try { string sep = f.ActualSep; if (string.IsNullOrWhiteSpace(sep)) { list.Add(f.CType.Apply(this, f.Remapper, stream, ass)); } else { list.Add(f.CType.Apply(this, f.Remapper, new ExcelStream(stream.ReadCell(), sep, false), ass)); } } catch (Exception e) { throw new InvalidExcelDataException($"读取结构:{bean.FullName} 字段:{f.Name} 出错 ==> {e.Message}", e); } } return list; } public DType Accept(TBean type, object converter, ExcelStream x, DefAssembly ass) { var originBean = (DefBean)type.Bean; if (originBean.IsAbstractType) { string subType = x.Read().ToString(); if (subType.ToLower().Trim() == DefBean.BEAN_NULL_STR) { if (!type.IsNullable) { throw new InvalidExcelDataException($"type:{type.Bean.FullName}不是可空类型. 不能为空"); } return null; } string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType); DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType); if (implType == null) { throw new InvalidExcelDataException($"type:{fullType} 不是bean类型"); } return new DBean(originBean, implType, CreateBeanFields(implType, x, ass)); } else { if (type.IsNullable) { string subType = x.Read().ToString().Trim(); if (subType == DefBean.BEAN_NULL_STR) { return null; } else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name) { throw new Exception($"type:{type.Bean.FullName} 可空标识:{subType} 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})"); } } return new DBean(originBean, originBean, CreateBeanFields(originBean, x, ass)); } } // 容器类统统不支持 type.IsNullable // 因为貌似没意义? public List ReadList(TType type, object converter, ExcelStream stream, DefAssembly ass) { stream.NamedMode = false; string sep = type is TBean bean ? ((DefBean)bean.Bean).Sep : null; var datas = new List(); while (!stream.TryReadEOF()) { if (string.IsNullOrWhiteSpace(sep)) { datas.Add(type.Apply(this, converter, stream, ass)); } else { datas.Add(type.Apply(this, converter, new ExcelStream(stream.ReadCell(), sep, false), ass)); ; } } return datas; } public DType Accept(TArray type, object converter, ExcelStream x, DefAssembly ass) { return new DArray(type, ReadList(type.ElementType, converter, x, ass)); } public DType Accept(TList type, object converter, ExcelStream x, DefAssembly ass) { return new DList(type, ReadList(type.ElementType, converter, x, ass)); } public DType Accept(TSet type, object converter, ExcelStream x, DefAssembly ass) { return new DSet(type, ReadList(type.ElementType, converter, x, ass)); } public DType Accept(TMap type, object converter, ExcelStream x, DefAssembly ass) { x.NamedMode = false; string sep = type.ValueType is TBean bean ? ((DefBean)bean.Bean).Sep : null; var datas = new Dictionary(); while (!x.TryReadEOF()) { var key = type.KeyType.Apply(this, null, x, ass); var value = string.IsNullOrWhiteSpace(sep) ? type.ValueType.Apply(this, null, x, ass) : type.ValueType.Apply(this, null, new ExcelStream(x.ReadCell(), sep, false), ass); if (!datas.TryAdd(key, value)) { throw new InvalidExcelDataException($"map 的 key:{key} 重复"); } } return new DMap(type, datas); } public DType Accept(TVector2 type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } return DataUtil.CreateVector(type, d.ToString()); } public DType Accept(TVector3 type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } return DataUtil.CreateVector(type, d.ToString()); } public DType Accept(TVector4 type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } return DataUtil.CreateVector(type, d.ToString()); } public DType Accept(TDateTime type, object converter, ExcelStream x, DefAssembly ass) { var d = x.Read(); if (CheckNull(type.IsNullable, d)) { return null; } return DataUtil.CreateDateTime(d.ToString()); } } }