mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-12-02 03:47:41 +08:00
ColumnHelper, CustomPropertyHelper, FileHelper, TypeHelper code refacturing
This commit is contained in:
parent
eb3bf99211
commit
9407cb9c4b
@ -7,7 +7,8 @@
|
|||||||
public class ExcelColumnIndexAttribute : Attribute
|
public class ExcelColumnIndexAttribute : Attribute
|
||||||
{
|
{
|
||||||
public int ExcelColumnIndex { get; set; }
|
public int ExcelColumnIndex { get; set; }
|
||||||
public ExcelColumnIndexAttribute(string columnName) => Init(Helpers.GetColumnIndex(columnName));
|
public ExcelColumnIndexAttribute(string columnName) => Init(ColumnHelper
|
||||||
|
.GetColumnIndex(columnName));
|
||||||
public ExcelColumnIndexAttribute(int columnIndex) => Init(columnIndex);
|
public ExcelColumnIndexAttribute(int columnIndex) => Init(columnIndex);
|
||||||
|
|
||||||
private void Init(int columnIndex)
|
private void Init(int columnIndex)
|
||||||
|
@ -5,7 +5,6 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static MiniExcelLibs.Utils.Helpers;
|
|
||||||
|
|
||||||
namespace MiniExcelLibs.Csv
|
namespace MiniExcelLibs.Csv
|
||||||
{
|
{
|
||||||
@ -43,7 +42,7 @@ namespace MiniExcelLibs.Csv
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell = Helpers.GetEmptyExpandoObject(headRows);
|
var cell = CustomPropertyHelper.GetEmptyExpandoObject(headRows);
|
||||||
for (int i = 0; i <= read.Length - 1; i++)
|
for (int i = 0; i <= read.Length - 1; i++)
|
||||||
cell[headRows[i]] = read[i];
|
cell[headRows[i]] = read[i];
|
||||||
|
|
||||||
@ -54,9 +53,9 @@ namespace MiniExcelLibs.Csv
|
|||||||
|
|
||||||
//body
|
//body
|
||||||
{
|
{
|
||||||
var cell = Helpers.GetEmptyExpandoObject(read.Length - 1, 0);
|
var cell = CustomPropertyHelper.GetEmptyExpandoObject(read.Length - 1, 0);
|
||||||
for (int i = 0; i <= read.Length - 1; i++)
|
for (int i = 0; i <= read.Length - 1; i++)
|
||||||
cell[Helpers.GetAlphabetColumnName(i)] = read[i];
|
cell[ColumnHelper.GetAlphabetColumnName(i)] = read[i];
|
||||||
yield return cell;
|
yield return cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +79,7 @@ namespace MiniExcelLibs.Csv
|
|||||||
row = reader.ReadLine();
|
row = reader.ReadLine();
|
||||||
read = Split(cf, row);
|
read = Split(cf, row);
|
||||||
|
|
||||||
var props = Helpers.GetExcelCustomPropertyInfos(type, read);
|
var props = CustomPropertyHelper.GetExcelCustomPropertyInfos(type, read);
|
||||||
var index = 0;
|
var index = 0;
|
||||||
foreach (var v in read)
|
foreach (var v in read)
|
||||||
{
|
{
|
||||||
@ -112,7 +111,7 @@ namespace MiniExcelLibs.Csv
|
|||||||
if (itemValue == null)
|
if (itemValue == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
newV = TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell);
|
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static MiniExcelLibs.Utils.Helpers;
|
|
||||||
|
|
||||||
namespace MiniExcelLibs.Csv
|
namespace MiniExcelLibs.Csv
|
||||||
{
|
{
|
||||||
@ -72,7 +71,7 @@ namespace MiniExcelLibs.Csv
|
|||||||
{
|
{
|
||||||
mode = "Properties";
|
mode = "Properties";
|
||||||
genericType = item.GetType();
|
genericType = item.GetType();
|
||||||
props = Helpers.GetSaveAsProperties(genericType);
|
props = CustomPropertyHelper.GetSaveAsProperties(genericType);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
public static IEnumerable<T> Query<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
public static IEnumerable<T> Query<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||||
{
|
{
|
||||||
using (var stream = Helpers.OpenSharedRead(path))
|
using (var stream = FileHelper.OpenSharedRead(path))
|
||||||
foreach (var item in Query<T>(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
|
foreach (var item in Query<T>(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
|
||||||
yield return item; //Foreach yield return twice reason : https://stackoverflow.com/questions/66791982/ienumerable-extract-code-lazy-loading-show-stream-was-not-readable
|
yield return item; //Foreach yield return twice reason : https://stackoverflow.com/questions/66791982/ienumerable-extract-code-lazy-loading-show-stream-was-not-readable
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
public static IEnumerable<dynamic> Query(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
public static IEnumerable<dynamic> Query(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||||
{
|
{
|
||||||
using (var stream = Helpers.OpenSharedRead(path))
|
using (var stream = FileHelper.OpenSharedRead(path))
|
||||||
foreach (var item in Query(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
|
foreach (var item in Query(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static DataTable QueryAsDataTable(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
public static DataTable QueryAsDataTable(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||||
{
|
{
|
||||||
using (var stream = Helpers.OpenSharedRead(path))
|
using (var stream = FileHelper.OpenSharedRead(path))
|
||||||
return QueryAsDataTable(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration);
|
return QueryAsDataTable(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@
|
|||||||
|
|
||||||
public static List<string> GetSheetNames(string path)
|
public static List<string> GetSheetNames(string path)
|
||||||
{
|
{
|
||||||
using (var stream = Helpers.OpenSharedRead(path))
|
using (var stream = FileHelper.OpenSharedRead(path))
|
||||||
return GetSheetNames(stream);
|
return GetSheetNames(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
public static ICollection<string> GetColumns(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
public static ICollection<string> GetColumns(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||||
{
|
{
|
||||||
using (var stream = Helpers.OpenSharedRead(path))
|
using (var stream = FileHelper.OpenSharedRead(path))
|
||||||
return GetColumns(stream, useHeaderRow, sheetName, excelType, startCell, configuration);
|
return GetColumns(stream, useHeaderRow, sheetName, excelType, startCell, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ using System.IO.Compression;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using static MiniExcelLibs.Utils.Helpers;
|
|
||||||
|
|
||||||
namespace MiniExcelLibs.OpenXml
|
namespace MiniExcelLibs.OpenXml
|
||||||
{
|
{
|
||||||
@ -370,7 +369,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
|
|
||||||
private static IDictionary<string, object> GetCell(bool useHeaderRow, int maxColumnIndex, Dictionary<int, string> headRows, int startColumnIndex)
|
private static IDictionary<string, object> GetCell(bool useHeaderRow, int maxColumnIndex, Dictionary<int, string> headRows, int startColumnIndex)
|
||||||
{
|
{
|
||||||
return useHeaderRow ? Helpers.GetEmptyExpandoObject(headRows) : Helpers.GetEmptyExpandoObject(maxColumnIndex, startColumnIndex);
|
return useHeaderRow ? CustomPropertyHelper.GetEmptyExpandoObject(headRows) : CustomPropertyHelper.GetEmptyExpandoObject(maxColumnIndex, startColumnIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Dictionary<int, string> headRows, ref bool isFirstRow, ref IDictionary<string, object> cell, int columnIndex)
|
private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Dictionary<int, string> headRows, ref bool isFirstRow, ref IDictionary<string, object> cell, int columnIndex)
|
||||||
@ -395,7 +394,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//if not using First Head then using A,B,C as index
|
//if not using First Head then using A,B,C as index
|
||||||
cell[Helpers.GetAlphabetColumnName(columnIndex)] = cellValue;
|
cell[ColumnHelper.GetAlphabetColumnName(columnIndex)] = cellValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +412,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
//TODO: alert don't duplicate column name
|
//TODO: alert don't duplicate column name
|
||||||
props = Helpers.GetExcelCustomPropertyInfos(type, headers);
|
props = CustomPropertyHelper.GetExcelCustomPropertyInfos(type, headers);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
var v = new T();
|
var v = new T();
|
||||||
@ -428,7 +427,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
if (itemValue == null)
|
if (itemValue == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
newV = TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell);
|
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rowIndex++;
|
rowIndex++;
|
||||||
|
@ -9,7 +9,6 @@ using System.IO.Compression;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static MiniExcelLibs.Utils.Helpers;
|
|
||||||
|
|
||||||
namespace MiniExcelLibs.OpenXml
|
namespace MiniExcelLibs.OpenXml
|
||||||
{
|
{
|
||||||
@ -139,7 +138,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
throw new NotImplementedException($"MiniExcel not support only {genericType.Name} value generic type");
|
throw new NotImplementedException($"MiniExcel not support only {genericType.Name} value generic type");
|
||||||
else if (genericType == typeof(string) || genericType == typeof(DateTime) || genericType == typeof(Guid))
|
else if (genericType == typeof(string) || genericType == typeof(DateTime) || genericType == typeof(Guid))
|
||||||
throw new NotImplementedException($"MiniExcel not support only {genericType.Name} generic type");
|
throw new NotImplementedException($"MiniExcel not support only {genericType.Name} generic type");
|
||||||
props = Helpers.GetSaveAsProperties(genericType);
|
props = CustomPropertyHelper.GetSaveAsProperties(genericType);
|
||||||
maxColumnIndex = props.Count;
|
maxColumnIndex = props.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +316,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
type = p.ExcludeNullableType; //sometime it doesn't need to re-get type like prop
|
type = p.ExcludeNullableType; //sometime it doesn't need to re-get type like prop
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers.IsNumericType(type))
|
if (TypeHelper.IsNumericType(type))
|
||||||
{
|
{
|
||||||
t = "n";
|
t = "n";
|
||||||
v = value.ToString();
|
v = value.ToString();
|
||||||
@ -476,9 +475,9 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
else if (maxColumnIndex == 1)
|
else if (maxColumnIndex == 1)
|
||||||
dimensionRef = $"A{maxRowIndex}";
|
dimensionRef = $"A{maxRowIndex}";
|
||||||
else if (maxRowIndex == 0)
|
else if (maxRowIndex == 0)
|
||||||
dimensionRef = $"A1:{Helpers.GetAlphabetColumnName(maxColumnIndex - 1)}1";
|
dimensionRef = $"A1:{ColumnHelper.GetAlphabetColumnName(maxColumnIndex - 1)}1";
|
||||||
else
|
else
|
||||||
dimensionRef = $"A1:{Helpers.GetAlphabetColumnName(maxColumnIndex - 1)}{maxRowIndex}";
|
dimensionRef = $"A1:{ColumnHelper.GetAlphabetColumnName(maxColumnIndex - 1)}{maxRowIndex}";
|
||||||
return dimensionRef;
|
return dimensionRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,31 +57,31 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
|
|
||||||
//TODO: width,height
|
//TODO: width,height
|
||||||
var xy1 = refs[0];
|
var xy1 = refs[0];
|
||||||
X1 = Helpers.GetColumnIndex(StringHelper.GetLetter(refs[0]));
|
X1 = ColumnHelper.GetColumnIndex(StringHelper.GetLetter(refs[0]));
|
||||||
Y1 = StringHelper.GetNumber(xy1);
|
Y1 = StringHelper.GetNumber(xy1);
|
||||||
|
|
||||||
var xy2 = refs[1];
|
var xy2 = refs[1];
|
||||||
X2 = Helpers.GetColumnIndex(StringHelper.GetLetter(refs[1]));
|
X2 = ColumnHelper.GetColumnIndex(StringHelper.GetLetter(refs[1]));
|
||||||
Y2 = StringHelper.GetNumber(xy2);
|
Y2 = StringHelper.GetNumber(xy2);
|
||||||
|
|
||||||
Width = Math.Abs(X1 - X2) + 1; ;
|
Width = Math.Abs(X1 - X2) + 1; ;
|
||||||
Height = Math.Abs(Y1 - Y2) + 1;
|
Height = Math.Abs(Y1 - Y2) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string XY1 { get { return $"{Helpers.GetAlphabetColumnName(X1)}{Y1}"; } }
|
public string XY1 { get { return $"{ColumnHelper.GetAlphabetColumnName(X1)}{Y1}"; } }
|
||||||
public int X1 { get; set; }
|
public int X1 { get; set; }
|
||||||
public int Y1 { get; set; }
|
public int Y1 { get; set; }
|
||||||
public string XY2 { get { return $"{Helpers.GetAlphabetColumnName(X2)}{Y2}"; } }
|
public string XY2 { get { return $"{ColumnHelper.GetAlphabetColumnName(X2)}{Y2}"; } }
|
||||||
public int X2 { get; set; }
|
public int X2 { get; set; }
|
||||||
public int Y2 { get; set; }
|
public int Y2 { get; set; }
|
||||||
public string Ref { get { return $"{Helpers.GetAlphabetColumnName(X1)}{Y1}:{Helpers.GetAlphabetColumnName(X2)}{Y2}"; } }
|
public string Ref { get { return $"{ColumnHelper.GetAlphabetColumnName(X1)}{Y1}:{ColumnHelper.GetAlphabetColumnName(X2)}{Y2}"; } }
|
||||||
public XmlElement MergeCell { get; set; }
|
public XmlElement MergeCell { get; set; }
|
||||||
public int Width { get; internal set; }
|
public int Width { get; internal set; }
|
||||||
public int Height { get; internal set; }
|
public int Height { get; internal set; }
|
||||||
|
|
||||||
public string ToXmlString(string prefix)
|
public string ToXmlString(string prefix)
|
||||||
{
|
{
|
||||||
return $"<{prefix}mergeCell ref=\"{Helpers.GetAlphabetColumnName(X1)}{Y1}:{Helpers.GetAlphabetColumnName(X2)}{Y2}\"/>";
|
return $"<{prefix}mergeCell ref=\"{ColumnHelper.GetAlphabetColumnName(X1)}{Y1}:{ColumnHelper.GetAlphabetColumnName(X2)}{Y2}\"/>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,7 +520,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
{
|
{
|
||||||
c.SetAttribute("t", "str");
|
c.SetAttribute("t", "str");
|
||||||
}
|
}
|
||||||
else if (Helpers.IsNumericType(type))
|
else if (TypeHelper.IsNumericType(type))
|
||||||
{
|
{
|
||||||
c.SetAttribute("t", "n");
|
c.SetAttribute("t", "n");
|
||||||
}
|
}
|
||||||
@ -568,7 +568,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
{
|
{
|
||||||
c.SetAttribute("t", "str");
|
c.SetAttribute("t", "str");
|
||||||
}
|
}
|
||||||
else if (Helpers.IsNumericType(type))
|
else if (TypeHelper.IsNumericType(type))
|
||||||
{
|
{
|
||||||
c.SetAttribute("t", "n");
|
c.SetAttribute("t", "n");
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
|
|
||||||
public void SaveAsByTemplate(string templatePath, object value)
|
public void SaveAsByTemplate(string templatePath, object value)
|
||||||
{
|
{
|
||||||
using (var stream = Helpers.OpenSharedRead(templatePath))
|
using (var stream = FileHelper.OpenSharedRead(templatePath))
|
||||||
SaveAsByTemplateImpl(stream, value);
|
SaveAsByTemplateImpl(stream, value);
|
||||||
}
|
}
|
||||||
public void SaveAsByTemplate(byte[] templateBtyes, object value)
|
public void SaveAsByTemplate(byte[] templateBtyes, object value)
|
||||||
|
67
src/MiniExcel/Utils/ColumnHelper.cs
Normal file
67
src/MiniExcel/Utils/ColumnHelper.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
namespace MiniExcelLibs.Utils
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
// For Row/Column Index
|
||||||
|
internal static partial class ColumnHelper
|
||||||
|
{
|
||||||
|
private const int GENERAL_COLUMN_INDEX = 255;
|
||||||
|
private const int MAX_COLUMN_INDEX = 16383;
|
||||||
|
private static Dictionary<int, string> _IntMappingAlphabet;
|
||||||
|
private static Dictionary<string, int> _AlphabetMappingInt;
|
||||||
|
static ColumnHelper()
|
||||||
|
{
|
||||||
|
if (_IntMappingAlphabet == null && _AlphabetMappingInt == null)
|
||||||
|
{
|
||||||
|
_IntMappingAlphabet = new Dictionary<int, string>();
|
||||||
|
_AlphabetMappingInt = new Dictionary<string, int>();
|
||||||
|
for (int i = 0; i <= GENERAL_COLUMN_INDEX; i++)
|
||||||
|
{
|
||||||
|
_IntMappingAlphabet.Add(i, IntToLetters(i));
|
||||||
|
_AlphabetMappingInt.Add(IntToLetters(i), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetAlphabetColumnName(int columnIndex)
|
||||||
|
{
|
||||||
|
CheckAndSetMaxColumnIndex(columnIndex);
|
||||||
|
return _IntMappingAlphabet[columnIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetColumnIndex(string columnName)
|
||||||
|
{
|
||||||
|
var columnIndex = _AlphabetMappingInt[columnName];
|
||||||
|
CheckAndSetMaxColumnIndex(columnIndex);
|
||||||
|
return columnIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckAndSetMaxColumnIndex(int columnIndex)
|
||||||
|
{
|
||||||
|
if (columnIndex >= _IntMappingAlphabet.Count)
|
||||||
|
{
|
||||||
|
if (columnIndex > MAX_COLUMN_INDEX)
|
||||||
|
throw new InvalidDataException($"ColumnIndex {columnIndex} over excel vaild max index.");
|
||||||
|
for (int i = _IntMappingAlphabet.Count; i <= columnIndex; i++)
|
||||||
|
{
|
||||||
|
_IntMappingAlphabet.Add(i, IntToLetters(i));
|
||||||
|
_AlphabetMappingInt.Add(IntToLetters(i), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string IntToLetters(int value)
|
||||||
|
{
|
||||||
|
value = value + 1;
|
||||||
|
string result = string.Empty;
|
||||||
|
while (--value >= 0)
|
||||||
|
{
|
||||||
|
result = (char)('A' + value % 26) + result;
|
||||||
|
value /= 26;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
150
src/MiniExcel/Utils/CustomPropertyHelper.cs
Normal file
150
src/MiniExcel/Utils/CustomPropertyHelper.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
namespace MiniExcelLibs.Utils
|
||||||
|
{
|
||||||
|
using MiniExcelLibs.Attributes;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
internal class ExcelCustomPropertyInfo
|
||||||
|
{
|
||||||
|
public int? ExcelColumnIndex { get; set; }
|
||||||
|
public string ExcelColumnName { get; set; }
|
||||||
|
public PropertyInfo Property { get; set; }
|
||||||
|
public Type ExcludeNullableType { get; set; }
|
||||||
|
public bool Nullable { get; internal set; }
|
||||||
|
public string ExcelFormat { get; internal set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static partial class CustomPropertyHelper
|
||||||
|
{
|
||||||
|
internal static IDictionary<string, object> GetEmptyExpandoObject(int maxColumnIndex, int startCellIndex)
|
||||||
|
{
|
||||||
|
// TODO: strong type mapping can ignore this
|
||||||
|
// TODO: it can recode better performance
|
||||||
|
var cell = (IDictionary<string, object>)new ExpandoObject();
|
||||||
|
for (int i = startCellIndex; i <= maxColumnIndex; i++)
|
||||||
|
{
|
||||||
|
var key = ColumnHelper.GetAlphabetColumnName(i);
|
||||||
|
if (!cell.ContainsKey(key))
|
||||||
|
cell.Add(key, null);
|
||||||
|
}
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IDictionary<string, object> GetEmptyExpandoObject(Dictionary<int, string> hearrows)
|
||||||
|
{
|
||||||
|
// TODO: strong type mapping can ignore this
|
||||||
|
// TODO: it can recode better performance
|
||||||
|
var cell = (IDictionary<string, object>)new ExpandoObject();
|
||||||
|
foreach (var hr in hearrows)
|
||||||
|
if (!cell.ContainsKey(hr.Value))
|
||||||
|
cell.Add(hr.Value, null);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<ExcelCustomPropertyInfo> GetSaveAsProperties(this Type type)
|
||||||
|
{
|
||||||
|
List<ExcelCustomPropertyInfo> props = GetExcelPropertyInfo(type, BindingFlags.Public | BindingFlags.Instance)
|
||||||
|
.Where(prop => prop.Property.GetGetMethod() != null && !prop.Property.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore))
|
||||||
|
.ToList() /*ignore without set*/;
|
||||||
|
|
||||||
|
if (props.Count == 0)
|
||||||
|
throw new InvalidOperationException($"{type.Name} un-ignore properties count can't be 0");
|
||||||
|
|
||||||
|
// https://github.com/shps951023/MiniExcel/issues/142
|
||||||
|
//TODO: need optimize performance
|
||||||
|
{
|
||||||
|
var withCustomIndexProps = props.Where(w => w.ExcelColumnIndex != null && w.ExcelColumnIndex > -1);
|
||||||
|
if (withCustomIndexProps.GroupBy(g => g.ExcelColumnIndex).Any(_ => _.Count() > 1))
|
||||||
|
throw new InvalidOperationException($"Duplicate column name");
|
||||||
|
|
||||||
|
var maxColumnIndex = props.Count - 1;
|
||||||
|
if (withCustomIndexProps.Any())
|
||||||
|
maxColumnIndex = Math.Max((int)withCustomIndexProps.Max(w => w.ExcelColumnIndex), maxColumnIndex);
|
||||||
|
|
||||||
|
var withoutCustomIndexProps = props.Where(w => w.ExcelColumnIndex == null).ToList();
|
||||||
|
|
||||||
|
List<ExcelCustomPropertyInfo> newProps = new List<ExcelCustomPropertyInfo>();
|
||||||
|
var index = 0;
|
||||||
|
for (int i = 0; i <= maxColumnIndex; i++)
|
||||||
|
{
|
||||||
|
var p1 = withCustomIndexProps.SingleOrDefault(s => s.ExcelColumnIndex == i);
|
||||||
|
if (p1 != null)
|
||||||
|
{
|
||||||
|
newProps.Add(p1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var p2 = withoutCustomIndexProps.ElementAtOrDefault(index);
|
||||||
|
if (p2 == null)
|
||||||
|
{
|
||||||
|
newProps.Add(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p2.ExcelColumnIndex = i;
|
||||||
|
newProps.Add(p2);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<ExcelCustomPropertyInfo> GetExcelCustomPropertyInfos(Type type, string[] headers)
|
||||||
|
{
|
||||||
|
List<ExcelCustomPropertyInfo> props = GetExcelPropertyInfo(type, BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
|
||||||
|
.Where(prop => prop.Property.GetSetMethod() != null && !prop.Property.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore))
|
||||||
|
.ToList() /*ignore without set*/;
|
||||||
|
|
||||||
|
if (props.Count == 0)
|
||||||
|
throw new InvalidOperationException($"{type.Name} un-ignore properties count can't be 0");
|
||||||
|
|
||||||
|
{
|
||||||
|
var withCustomIndexProps = props.Where(w => w.ExcelColumnIndex != null && w.ExcelColumnIndex > -1);
|
||||||
|
if (withCustomIndexProps.GroupBy(g => g.ExcelColumnIndex).Any(_ => _.Count() > 1))
|
||||||
|
throw new InvalidOperationException($"Duplicate column name");
|
||||||
|
|
||||||
|
foreach (var p in props)
|
||||||
|
{
|
||||||
|
if (p.ExcelColumnIndex != null)
|
||||||
|
{
|
||||||
|
if (p.ExcelColumnIndex >= headers.Length)
|
||||||
|
throw new ArgumentException($"ExcelColumnIndex {p.ExcelColumnIndex} over haeder max index {headers.Length}");
|
||||||
|
p.ExcelColumnName = headers[(int)p.ExcelColumnIndex];
|
||||||
|
if (p.ExcelColumnName == null)
|
||||||
|
throw new InvalidOperationException($"{p.Property.DeclaringType.Name} {p.Property.Name}'s ExcelColumnIndex {p.ExcelColumnIndex} can't find excel column name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<ExcelCustomPropertyInfo> GetExcelPropertyInfo(Type type, BindingFlags bindingFlags)
|
||||||
|
{
|
||||||
|
return type.GetProperties(bindingFlags)
|
||||||
|
// solve : https://github.com/shps951023/MiniExcel/issues/138
|
||||||
|
.Select(p =>
|
||||||
|
{
|
||||||
|
var gt = Nullable.GetUnderlyingType(p.PropertyType);
|
||||||
|
var excelNameAttr = p.GetAttribute<ExcelColumnNameAttribute>();
|
||||||
|
var excelIndexAttr = p.GetAttribute<ExcelColumnIndexAttribute>();
|
||||||
|
return new ExcelCustomPropertyInfo
|
||||||
|
{
|
||||||
|
Property = p,
|
||||||
|
ExcludeNullableType = gt ?? p.PropertyType,
|
||||||
|
Nullable = gt != null ? true : false,
|
||||||
|
ExcelColumnName = excelNameAttr?.ExcelColumnName ?? p.Name,
|
||||||
|
ExcelColumnIndex = excelIndexAttr?.ExcelColumnIndex,
|
||||||
|
ExcelFormat = p.GetAttribute<ExcelFormatAttribute>()?.Format,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/MiniExcel/Utils/FileHelper.cs
Normal file
10
src/MiniExcel/Utils/FileHelper.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace MiniExcelLibs.Utils
|
||||||
|
{
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
internal static partial class FileHelper
|
||||||
|
{
|
||||||
|
public static FileStream OpenSharedRead(string path) => File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,316 +0,0 @@
|
|||||||
namespace MiniExcelLibs.Utils
|
|
||||||
{
|
|
||||||
using MiniExcelLibs.Attributes;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Dynamic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
internal static partial class Helpers
|
|
||||||
{
|
|
||||||
public static FileStream OpenSharedRead(string path) => File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For Row/Column Index
|
|
||||||
internal static partial class Helpers
|
|
||||||
{
|
|
||||||
private const int GENERAL_COLUMN_INDEX = 255;
|
|
||||||
private const int MAX_COLUMN_INDEX = 16383;
|
|
||||||
private static Dictionary<int, string> _IntMappingAlphabet;
|
|
||||||
private static Dictionary<string, int> _AlphabetMappingInt;
|
|
||||||
static Helpers()
|
|
||||||
{
|
|
||||||
if (_IntMappingAlphabet == null && _AlphabetMappingInt == null)
|
|
||||||
{
|
|
||||||
_IntMappingAlphabet = new Dictionary<int, string>();
|
|
||||||
_AlphabetMappingInt = new Dictionary<string, int>();
|
|
||||||
for (int i = 0; i <= GENERAL_COLUMN_INDEX; i++)
|
|
||||||
{
|
|
||||||
_IntMappingAlphabet.Add(i, IntToLetters(i));
|
|
||||||
_AlphabetMappingInt.Add(IntToLetters(i), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetAlphabetColumnName(int columnIndex)
|
|
||||||
{
|
|
||||||
CheckAndSetMaxColumnIndex(columnIndex);
|
|
||||||
return _IntMappingAlphabet[columnIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetColumnIndex(string columnName)
|
|
||||||
{
|
|
||||||
var columnIndex = _AlphabetMappingInt[columnName];
|
|
||||||
CheckAndSetMaxColumnIndex(columnIndex);
|
|
||||||
return columnIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckAndSetMaxColumnIndex(int columnIndex)
|
|
||||||
{
|
|
||||||
if (columnIndex >= _IntMappingAlphabet.Count)
|
|
||||||
{
|
|
||||||
if (columnIndex > MAX_COLUMN_INDEX)
|
|
||||||
throw new InvalidDataException($"ColumnIndex {columnIndex} over excel vaild max index.");
|
|
||||||
for (int i = _IntMappingAlphabet.Count; i <= columnIndex; i++)
|
|
||||||
{
|
|
||||||
_IntMappingAlphabet.Add(i, IntToLetters(i));
|
|
||||||
_AlphabetMappingInt.Add(IntToLetters(i), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string IntToLetters(int value)
|
|
||||||
{
|
|
||||||
value = value + 1;
|
|
||||||
string result = string.Empty;
|
|
||||||
while (--value >= 0)
|
|
||||||
{
|
|
||||||
result = (char)('A' + value % 26) + result;
|
|
||||||
value /= 26;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static partial class Helpers
|
|
||||||
{
|
|
||||||
internal static IDictionary<string, object> GetEmptyExpandoObject(int maxColumnIndex, int startCellIndex)
|
|
||||||
{
|
|
||||||
// TODO: strong type mapping can ignore this
|
|
||||||
// TODO: it can recode better performance
|
|
||||||
var cell = (IDictionary<string, object>)new ExpandoObject();
|
|
||||||
for (int i = startCellIndex; i <= maxColumnIndex; i++)
|
|
||||||
{
|
|
||||||
var key = GetAlphabetColumnName(i);
|
|
||||||
if (!cell.ContainsKey(key))
|
|
||||||
cell.Add(key, null);
|
|
||||||
}
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static IDictionary<string, object> GetEmptyExpandoObject(Dictionary<int, string> hearrows)
|
|
||||||
{
|
|
||||||
// TODO: strong type mapping can ignore this
|
|
||||||
// TODO: it can recode better performance
|
|
||||||
var cell = (IDictionary<string, object>)new ExpandoObject();
|
|
||||||
foreach (var hr in hearrows)
|
|
||||||
if (!cell.ContainsKey(hr.Value))
|
|
||||||
cell.Add(hr.Value, null);
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<ExcelCustomPropertyInfo> GetSaveAsProperties(this Type type)
|
|
||||||
{
|
|
||||||
List<ExcelCustomPropertyInfo> props = GetExcelPropertyInfo(type, BindingFlags.Public | BindingFlags.Instance)
|
|
||||||
.Where(prop => prop.Property.GetGetMethod() != null && !prop.Property.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore))
|
|
||||||
.ToList() /*ignore without set*/;
|
|
||||||
|
|
||||||
if (props.Count == 0)
|
|
||||||
throw new InvalidOperationException($"{type.Name} un-ignore properties count can't be 0");
|
|
||||||
|
|
||||||
// https://github.com/shps951023/MiniExcel/issues/142
|
|
||||||
//TODO: need optimize performance
|
|
||||||
{
|
|
||||||
var withCustomIndexProps = props.Where(w => w.ExcelColumnIndex != null && w.ExcelColumnIndex > -1);
|
|
||||||
if (withCustomIndexProps.GroupBy(g => g.ExcelColumnIndex).Any(_ => _.Count() > 1))
|
|
||||||
throw new InvalidOperationException($"Duplicate column name");
|
|
||||||
|
|
||||||
var maxColumnIndex = props.Count - 1;
|
|
||||||
if (withCustomIndexProps.Any())
|
|
||||||
maxColumnIndex = Math.Max((int)withCustomIndexProps.Max(w => w.ExcelColumnIndex), maxColumnIndex);
|
|
||||||
|
|
||||||
var withoutCustomIndexProps = props.Where(w => w.ExcelColumnIndex == null).ToList();
|
|
||||||
|
|
||||||
List<ExcelCustomPropertyInfo> newProps = new List<ExcelCustomPropertyInfo>();
|
|
||||||
var index = 0;
|
|
||||||
for (int i = 0; i <= maxColumnIndex; i++)
|
|
||||||
{
|
|
||||||
var p1 = withCustomIndexProps.SingleOrDefault(s => s.ExcelColumnIndex == i);
|
|
||||||
if (p1 != null)
|
|
||||||
{
|
|
||||||
newProps.Add(p1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var p2 = withoutCustomIndexProps.ElementAtOrDefault(index);
|
|
||||||
if (p2 == null)
|
|
||||||
{
|
|
||||||
newProps.Add(null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p2.ExcelColumnIndex = i;
|
|
||||||
newProps.Add(p2);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newProps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ExcelCustomPropertyInfo
|
|
||||||
{
|
|
||||||
public int? ExcelColumnIndex { get; set; }
|
|
||||||
public string ExcelColumnName { get; set; }
|
|
||||||
public PropertyInfo Property { get; set; }
|
|
||||||
public Type ExcludeNullableType { get; set; }
|
|
||||||
public bool Nullable { get; internal set; }
|
|
||||||
public string ExcelFormat { get; internal set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<ExcelCustomPropertyInfo> GetExcelCustomPropertyInfos(Type type, string[] headers)
|
|
||||||
{
|
|
||||||
List<ExcelCustomPropertyInfo> props = GetExcelPropertyInfo(type, BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
|
|
||||||
.Where(prop => prop.Property.GetSetMethod() != null && !prop.Property.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore))
|
|
||||||
.ToList() /*ignore without set*/;
|
|
||||||
|
|
||||||
if (props.Count == 0)
|
|
||||||
throw new InvalidOperationException($"{type.Name} un-ignore properties count can't be 0");
|
|
||||||
|
|
||||||
{
|
|
||||||
var withCustomIndexProps = props.Where(w => w.ExcelColumnIndex != null && w.ExcelColumnIndex > -1);
|
|
||||||
if (withCustomIndexProps.GroupBy(g => g.ExcelColumnIndex).Any(_ => _.Count() > 1))
|
|
||||||
throw new InvalidOperationException($"Duplicate column name");
|
|
||||||
|
|
||||||
foreach (var p in props)
|
|
||||||
{
|
|
||||||
if (p.ExcelColumnIndex != null)
|
|
||||||
{
|
|
||||||
if (p.ExcelColumnIndex >= headers.Length)
|
|
||||||
throw new ArgumentException($"ExcelColumnIndex {p.ExcelColumnIndex} over haeder max index {headers.Length}");
|
|
||||||
p.ExcelColumnName = headers[(int)p.ExcelColumnIndex];
|
|
||||||
if (p.ExcelColumnName == null)
|
|
||||||
throw new InvalidOperationException($"{p.Property.DeclaringType.Name} {p.Property.Name}'s ExcelColumnIndex {p.ExcelColumnIndex} can't find excel column name");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<ExcelCustomPropertyInfo> GetExcelPropertyInfo(Type type, BindingFlags bindingFlags)
|
|
||||||
{
|
|
||||||
return type.GetProperties(bindingFlags)
|
|
||||||
// solve : https://github.com/shps951023/MiniExcel/issues/138
|
|
||||||
.Select(p =>
|
|
||||||
{
|
|
||||||
var gt = Nullable.GetUnderlyingType(p.PropertyType);
|
|
||||||
var excelNameAttr = p.GetAttribute<ExcelColumnNameAttribute>();
|
|
||||||
var excelIndexAttr = p.GetAttribute<ExcelColumnIndexAttribute>();
|
|
||||||
return new ExcelCustomPropertyInfo
|
|
||||||
{
|
|
||||||
Property = p,
|
|
||||||
ExcludeNullableType = gt ?? p.PropertyType,
|
|
||||||
Nullable = gt != null ? true : false,
|
|
||||||
ExcelColumnName = excelNameAttr?.ExcelColumnName ?? p.Name,
|
|
||||||
ExcelColumnIndex = excelIndexAttr?.ExcelColumnIndex,
|
|
||||||
ExcelFormat = p.GetAttribute<ExcelFormatAttribute>()?.Format,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsNumericType(Type type, bool isNullableUnderlyingType = false)
|
|
||||||
{
|
|
||||||
if (isNullableUnderlyingType)
|
|
||||||
type = Nullable.GetUnderlyingType(type) ?? type;
|
|
||||||
switch (Type.GetTypeCode(type))
|
|
||||||
{
|
|
||||||
//case TypeCode.Byte:
|
|
||||||
//case TypeCode.SByte:
|
|
||||||
case TypeCode.UInt16:
|
|
||||||
case TypeCode.UInt32:
|
|
||||||
case TypeCode.UInt64:
|
|
||||||
case TypeCode.Int16:
|
|
||||||
case TypeCode.Int32:
|
|
||||||
case TypeCode.Int64:
|
|
||||||
case TypeCode.Decimal:
|
|
||||||
case TypeCode.Double:
|
|
||||||
case TypeCode.Single:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object TypeMapping<T>(T v, ExcelCustomPropertyInfo pInfo, object newValue, object itemValue, int rowIndex, string startCell) where T : class, new()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return TypeMappingImpl(v, pInfo, ref newValue, itemValue);
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (ex is InvalidCastException || ex is FormatException)
|
|
||||||
{
|
|
||||||
var columnName = pInfo.ExcelColumnName ?? pInfo.Property.Name;
|
|
||||||
var startRowIndex = ReferenceHelper.ConvertCellToXY(startCell).Item2;
|
|
||||||
var errorRow = startRowIndex + rowIndex + 1;
|
|
||||||
throw new InvalidCastException($"ColumnName : {columnName}, CellRow : {errorRow}, Value : {itemValue}, it can't cast to {pInfo.Property.PropertyType.Name} type.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object TypeMappingImpl<T>(T v, ExcelCustomPropertyInfo pInfo, ref object newValue, object itemValue) where T : class, new()
|
|
||||||
{
|
|
||||||
if (pInfo.ExcludeNullableType == typeof(Guid))
|
|
||||||
{
|
|
||||||
newValue = Guid.Parse(itemValue.ToString());
|
|
||||||
}
|
|
||||||
else if (pInfo.ExcludeNullableType == typeof(DateTime))
|
|
||||||
{
|
|
||||||
// fix issue 257 https://github.com/shps951023/MiniExcel/issues/257
|
|
||||||
if (itemValue is DateTime || itemValue is DateTime?)
|
|
||||||
{
|
|
||||||
newValue = itemValue;
|
|
||||||
pInfo.Property.SetValue(v, newValue);
|
|
||||||
return newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var vs = itemValue?.ToString();
|
|
||||||
if (pInfo.ExcelFormat != null)
|
|
||||||
{
|
|
||||||
if (DateTime.TryParseExact(vs, pInfo.ExcelFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v))
|
|
||||||
{
|
|
||||||
newValue = _v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (DateTime.TryParse(vs, CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v))
|
|
||||||
newValue = _v;
|
|
||||||
else if (DateTime.TryParseExact(vs, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v2))
|
|
||||||
newValue = _v2;
|
|
||||||
else if (double.TryParse(vs, NumberStyles.None, CultureInfo.InvariantCulture, out var _d))
|
|
||||||
newValue = DateTimeHelper.FromOADate(_d);
|
|
||||||
else
|
|
||||||
throw new InvalidCastException($"{vs} can't cast to datetime");
|
|
||||||
}
|
|
||||||
else if (pInfo.ExcludeNullableType == typeof(bool))
|
|
||||||
{
|
|
||||||
var vs = itemValue.ToString();
|
|
||||||
if (vs == "1")
|
|
||||||
newValue = true;
|
|
||||||
else if (vs == "0")
|
|
||||||
newValue = false;
|
|
||||||
else
|
|
||||||
newValue = bool.Parse(vs);
|
|
||||||
}
|
|
||||||
else if (pInfo.Property.PropertyType == typeof(string))
|
|
||||||
{
|
|
||||||
newValue = XmlEncoder.DecodeString(itemValue?.ToString());
|
|
||||||
}
|
|
||||||
else if (pInfo.Property.PropertyType.IsEnum)
|
|
||||||
{
|
|
||||||
newValue = Enum.Parse(pInfo.Property.PropertyType, itemValue?.ToString(), true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Use pInfo.ExcludeNullableType to resolve : https://github.com/shps951023/MiniExcel/issues/138
|
|
||||||
newValue = Convert.ChangeType(itemValue, pInfo.ExcludeNullableType);
|
|
||||||
}
|
|
||||||
|
|
||||||
pInfo.Property.SetValue(v, newValue);
|
|
||||||
return newValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
115
src/MiniExcel/Utils/TypeHelper.cs
Normal file
115
src/MiniExcel/Utils/TypeHelper.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
namespace MiniExcelLibs.Utils
|
||||||
|
{
|
||||||
|
using MiniExcelLibs.Attributes;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
internal static partial class TypeHelper
|
||||||
|
{
|
||||||
|
public static bool IsNumericType(Type type, bool isNullableUnderlyingType = false)
|
||||||
|
{
|
||||||
|
if (isNullableUnderlyingType)
|
||||||
|
type = Nullable.GetUnderlyingType(type) ?? type;
|
||||||
|
switch (Type.GetTypeCode(type))
|
||||||
|
{
|
||||||
|
//case TypeCode.Byte:
|
||||||
|
//case TypeCode.SByte:
|
||||||
|
case TypeCode.UInt16:
|
||||||
|
case TypeCode.UInt32:
|
||||||
|
case TypeCode.UInt64:
|
||||||
|
case TypeCode.Int16:
|
||||||
|
case TypeCode.Int32:
|
||||||
|
case TypeCode.Int64:
|
||||||
|
case TypeCode.Decimal:
|
||||||
|
case TypeCode.Double:
|
||||||
|
case TypeCode.Single:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static object TypeMapping<T>(T v, ExcelCustomPropertyInfo pInfo, object newValue, object itemValue, int rowIndex, string startCell) where T : class, new()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return TypeMappingImpl(v, pInfo, ref newValue, itemValue);
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (ex is InvalidCastException || ex is FormatException)
|
||||||
|
{
|
||||||
|
var columnName = pInfo.ExcelColumnName ?? pInfo.Property.Name;
|
||||||
|
var startRowIndex = ReferenceHelper.ConvertCellToXY(startCell).Item2;
|
||||||
|
var errorRow = startRowIndex + rowIndex + 1;
|
||||||
|
throw new InvalidCastException($"ColumnName : {columnName}, CellRow : {errorRow}, Value : {itemValue}, it can't cast to {pInfo.Property.PropertyType.Name} type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object TypeMappingImpl<T>(T v, ExcelCustomPropertyInfo pInfo, ref object newValue, object itemValue) where T : class, new()
|
||||||
|
{
|
||||||
|
if (pInfo.ExcludeNullableType == typeof(Guid))
|
||||||
|
{
|
||||||
|
newValue = Guid.Parse(itemValue.ToString());
|
||||||
|
}
|
||||||
|
else if (pInfo.ExcludeNullableType == typeof(DateTime))
|
||||||
|
{
|
||||||
|
// fix issue 257 https://github.com/shps951023/MiniExcel/issues/257
|
||||||
|
if (itemValue is DateTime || itemValue is DateTime?)
|
||||||
|
{
|
||||||
|
newValue = itemValue;
|
||||||
|
pInfo.Property.SetValue(v, newValue);
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vs = itemValue?.ToString();
|
||||||
|
if (pInfo.ExcelFormat != null)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParseExact(vs, pInfo.ExcelFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v))
|
||||||
|
{
|
||||||
|
newValue = _v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (DateTime.TryParse(vs, CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v))
|
||||||
|
newValue = _v;
|
||||||
|
else if (DateTime.TryParseExact(vs, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var _v2))
|
||||||
|
newValue = _v2;
|
||||||
|
else if (double.TryParse(vs, NumberStyles.None, CultureInfo.InvariantCulture, out var _d))
|
||||||
|
newValue = DateTimeHelper.FromOADate(_d);
|
||||||
|
else
|
||||||
|
throw new InvalidCastException($"{vs} can't cast to datetime");
|
||||||
|
}
|
||||||
|
else if (pInfo.ExcludeNullableType == typeof(bool))
|
||||||
|
{
|
||||||
|
var vs = itemValue.ToString();
|
||||||
|
if (vs == "1")
|
||||||
|
newValue = true;
|
||||||
|
else if (vs == "0")
|
||||||
|
newValue = false;
|
||||||
|
else
|
||||||
|
newValue = bool.Parse(vs);
|
||||||
|
}
|
||||||
|
else if (pInfo.Property.PropertyType == typeof(string))
|
||||||
|
{
|
||||||
|
newValue = XmlEncoder.DecodeString(itemValue?.ToString());
|
||||||
|
}
|
||||||
|
else if (pInfo.Property.PropertyType.IsEnum)
|
||||||
|
{
|
||||||
|
newValue = Enum.Parse(pInfo.Property.PropertyType, itemValue?.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use pInfo.ExcludeNullableType to resolve : https://github.com/shps951023/MiniExcel/issues/138
|
||||||
|
newValue = Convert.ChangeType(itemValue, pInfo.ExcludeNullableType);
|
||||||
|
}
|
||||||
|
|
||||||
|
pInfo.Property.SetValue(v, newValue);
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user