diff --git a/PlayGround/PlayGround.csproj b/PlayGround/PlayGround.csproj
new file mode 100644
index 0000000..bbdfde2
--- /dev/null
+++ b/PlayGround/PlayGround.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+ 10.0
+
+
+
+ 10.0
+
+
+
+
+
+
+
diff --git a/PlayGround/Program.cs b/PlayGround/Program.cs
new file mode 100644
index 0000000..5264535
--- /dev/null
+++ b/PlayGround/Program.cs
@@ -0,0 +1,17 @@
+// See https://aka.ms/new-console-template for more information
+using Shane32.ExcelLinq.Tests.Models;
+
+Console.WriteLine("Hello, World!");
+
+
+
+using var stream1 = new System.IO.FileStream("test.xlsx", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
+var tt = new TestFileContext(stream1);
+var pp = tt.GetSheet();
+var xl = new TestFileContext();
+using var stream = new System.IO.FileStream("test.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
+var t = xl.ReadCsv(stream);
+
+
+var g = t;
+
diff --git a/Shane32.ExcelLinq.sln b/Shane32.ExcelLinq.sln
index 51962f3..59c53b1 100644
--- a/Shane32.ExcelLinq.sln
+++ b/Shane32.ExcelLinq.sln
@@ -39,6 +39,10 @@ Global
{83E2AC89-22B4-438D-92CF-FDA280B63CFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83E2AC89-22B4-438D-92CF-FDA280B63CFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83E2AC89-22B4-438D-92CF-FDA280B63CFD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs
index 9f8faeb..b3dee2b 100644
--- a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs
+++ b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs
@@ -21,6 +21,18 @@ public void NullConstructorsThrow()
Assert.ThrowsException(() => new TestFileContext((ExcelPackage)null));
}
+
+ [TestMethod]
+ public void ReadSampleCsvFile()
+ {
+ var xl = new TestFileContext();
+ using var stream1 = new System.IO.FileStream("test1.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
+ using var stream2 = new System.IO.FileStream("test2.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
+ xl.ReadCsv(stream1, "Sheet1");
+ xl.ReadCsv(stream2, "Sheet2");
+ ReadSample1File_test(xl);
+ }
+
[TestMethod]
public void ReadSample1File()
{
@@ -55,7 +67,8 @@ public void ReadAndWrite()
Assert.AreEqual(xl.GetSheet().Count, xl2.GetSheet().Count);
}
- public void ReadSample1File_test(TestFileContext xl) {
+ public void ReadSample1File_test(TestFileContext xl)
+ {
var sheet1 = xl.GetSheet();
var sheet2 = xl.GetSheet();
Assert.AreEqual(2, sheet1.Count);
diff --git a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs
index 4e719ec..b770e75 100644
--- a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs
+++ b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs
@@ -7,6 +7,7 @@ namespace Shane32.ExcelLinq.Tests.Models
{
public class TestFileContext : ExcelContext
{
+ public TestFileContext() : base() { }
public TestFileContext(System.IO.Stream stream) : base(stream) { }
public TestFileContext(string filename) : base(filename) { }
public TestFileContext(ExcelPackage excelPackage) : base(excelPackage) { }
@@ -14,12 +15,15 @@ public TestFileContext(ExcelPackage excelPackage) : base(excelPackage) { }
protected override void OnModelCreating(ExcelModelBuilder builder)
{
Action headerFormatter = range => {
+
range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
};
+ builder.ReadCsv();
+
Action numberFormatter = range => range.Style.Numberformat.Format = "#,##0.00";
var sheet1 = builder.Sheet();
- sheet1.Column(x => x.Date)
+ sheet1.Column(x => x.Date).AlternateName("its a date")
.HeaderFormatter(headerFormatter)
.ColumnFormatter(range => range.Style.Numberformat.Format = "MM/dd/yyyy");
sheet1.Column(x => x.Quantity)
@@ -27,7 +31,7 @@ protected override void OnModelCreating(ExcelModelBuilder builder)
.ColumnFormatter(range => range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center);
sheet1.Column(x => x.Description)
.HeaderFormatter(headerFormatter);
- sheet1.Column(x => x.Amount)
+ sheet1.Column(x => x.Amount).AlternateName("some amount")
.HeaderFormatter(headerFormatter)
.ColumnFormatter(numberFormatter);
sheet1.Column(x => x.Total)
@@ -62,11 +66,11 @@ protected override void OnModelCreating(ExcelModelBuilder builder)
sheet1.WriteRangeLocator(worksheet => worksheet.Cells[3, 1]);
sheet1.WritePolisher((worksheet, range) => {
worksheet.Calculate();
- for (int col = 1; col <= worksheet.Dimension.End.Column; col++) {
- var column = worksheet.Column(col);
- column.AutoFit();
- column.Width *= 1.2;
- }
+ //for (int col = 1; col <= worksheet.Dimension.End.Column; col++) {
+ // var column = worksheet.Column(col);
+ // column.AutoFit();
+ // column.Width *= 1.2;
+ //}
worksheet.Cells[1, 1].Value = "This is a test header";
});
@@ -74,7 +78,7 @@ protected override void OnModelCreating(ExcelModelBuilder builder)
sheet2.Column(x => x.IntColumn);
sheet2.Column(x => x.FloatColumn);
sheet2.Column(x => x.DoubleColumn);
- sheet2.Column(x => x.StringColumn);
+ sheet2.Column(x => x.StringColumn).AlternateName("be a string column");
sheet2.Column(x => x.BooleanColumn);
sheet2.Column(x => x.DateTimeColumn)
.ColumnFormatter(range => range.Style.Numberformat.Format = "MM/dd/yyyy hh:mm AM/PM");
diff --git a/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj b/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj
index 78dd6b2..db584d8 100644
--- a/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj
+++ b/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj
@@ -7,6 +7,24 @@
netcoreapp3.1;net5.0;net6.0;net462;net48
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
all
diff --git a/src/Shane32.ExcelLinq.Tests/test.csv b/src/Shane32.ExcelLinq.Tests/test.csv
new file mode 100644
index 0000000..93d5d03
--- /dev/null
+++ b/src/Shane32.ExcelLinq.Tests/test.csv
@@ -0,0 +1,10 @@
+IntColumn,FloatColumn,DoubleColumn,StringColumn,BooleanColumn,DateTimeColumn,TimespanColumn,UriColumn,GuidColumn,NullableIntColumn
+1,1,1,test,TRUE,2-Aug,02:00 PM,http://localhost/test,f1dc7e7d-d63e-4279-8dfd-cecb6e26cda8,3
+1.1,1.1,1.1,test2,FALSE,8/1/2020,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3.1
+1,1.1,1.1,test2,true,8/3/20,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3
+1.1,1.1,1.1,test2,yes,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,NO,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,y,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,N,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,1,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,0,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
diff --git a/src/Shane32.ExcelLinq.Tests/test1.csv b/src/Shane32.ExcelLinq.Tests/test1.csv
new file mode 100644
index 0000000..c04c7dc
--- /dev/null
+++ b/src/Shane32.ExcelLinq.Tests/test1.csv
@@ -0,0 +1,3 @@
+Date,Quantity,Description,Amount, Total ,Notes
+7/1/2020,52,Widgets,45.99 ," $2,391.48 ",
+7/23/2020,22,Bolts,2.54 , $55.88 ,Each bolt is a set of two
diff --git a/src/Shane32.ExcelLinq.Tests/test2.csv b/src/Shane32.ExcelLinq.Tests/test2.csv
new file mode 100644
index 0000000..b5d2660
--- /dev/null
+++ b/src/Shane32.ExcelLinq.Tests/test2.csv
@@ -0,0 +1,10 @@
+IntColumn,FloatColumn,DoubleColumn,StringColumn,BooleanColumn,DateTimeColumn,TimespanColumn,UriColumn,GuidColumn,NullableIntColumn
+1,1,1,test,TRUE,2-Aug,2:00 PM,http://localhost/test,f1dc7e7d-d63e-4279-8dfd-cecb6e26cda8,3
+1.1,1.1,1.1,test2,FALSE,8/1/2020,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3.1
+1,1.1,1.1,test2,true,8/3/20,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3
+1.1,1.1,1.1,test2,yes,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,NO,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,y,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,N,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,1,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
+1.1,1.1,1.1,test2,0,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,
diff --git a/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs b/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs
index 4c95833..2b69737 100644
--- a/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs
+++ b/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs
@@ -11,12 +11,13 @@ public class ExcelModelBuilder : IExcelModel, ISheetModelLookup
internal Dictionary _sheetDictionary = new Dictionary();
internal Dictionary _typeDictionary = new Dictionary();
private bool _ignoreSheetNames;
+ public bool _readCsv;
public SheetModelBuilder Sheet() where T : new()
{
return Sheet(typeof(T).Name);
}
-
+
public SheetModelBuilder Sheet(string name) where T : new()
{
if (name == null)
@@ -34,6 +35,8 @@ public void IgnoreSheetNames()
{
_ignoreSheetNames = true;
}
+ bool IExcelModel.ReadCsv => _readCsv;
+ public void ReadCsv() => _readCsv = true;
IEnumerator IEnumerable.GetEnumerator() => _sheets.GetEnumerator();
diff --git a/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs b/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs
index fc582f4..afb3ba9 100644
--- a/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs
+++ b/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs
@@ -32,6 +32,7 @@ public SheetModelBuilder(ExcelModelBuilder excelModelBuilder, string name)
excelModelBuilder._typeDictionary.Add(typeof(T), this);
}
+
public SheetModelBuilder AlternateName(string name)
{
if (string.IsNullOrWhiteSpace(name))
diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs
index bb12b41..6e68fa1 100644
--- a/src/Shane32.ExcelLinq/ExcelContext.cs
+++ b/src/Shane32.ExcelLinq/ExcelContext.cs
@@ -3,11 +3,14 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Linq.Expressions;
using System.Reflection;
using OfficeOpenXml;
using Shane32.ExcelLinq.Builders;
using Shane32.ExcelLinq.Exceptions;
using Shane32.ExcelLinq.Models;
+using NotVisualBasic.FileIO;
+using System.Globalization;
namespace Shane32.ExcelLinq
{
@@ -107,12 +110,31 @@ protected ExcelContext(ExcelPackage excelPackage) : this()
_initialized = true;
}
- //internal ExcelContext(IExcelModel model, ExcelPackage excelPackage) : this(model)
- //{
- // _initialized = false;
- // _sheets = InitializeReadFile(excelPackage);
- // _initialized = true;
- //}
+ public void ReadCsv(Stream stream, IFormatProvider formatProvider = null)
+ {
+ if (!_initialized)
+ throw new InvalidOperationException();
+ var index = _typeLookup[typeof(T)];
+ _sheets[index] = (List)OnReadCsv(stream, Model.Sheets[index], formatProvider ?? CultureInfo.CurrentCulture);
+ }
+
+ public void ReadCsv(Stream stream, string name, IFormatProvider formatProvider = null)
+ {
+ if (!_initialized)
+ throw new InvalidOperationException();
+ var index = _sheetNameLookup[name];
+ _sheets[index] = (List)OnReadCsv(stream, Model.Sheets[index], formatProvider ?? CultureInfo.CurrentCulture);
+ }
+
+ public static TContext OpenCsv(Stream stream, IFormatProvider formatProvider = null)
+ where TContext : ExcelContext, new()
+ {
+ var context = new TContext();
+ if (context._sheets.Count != 1)
+ throw new InvalidOperationException("Cannot open CSV file with multiple sheets.");
+ context.OnReadCsv(stream, context.Model.Sheets[0], formatProvider ?? CultureInfo.CurrentCulture);
+ return context;
+ }
private List InitializeReadFile(ExcelPackage excelFile)
{
@@ -146,6 +168,8 @@ protected IList CreateListForSheet(Type type, int capacity)
protected abstract void OnModelCreating(ExcelModelBuilder modelBuilder);
+
+
///
/// Parses an and returns all of the data within all the worksheets.
///
@@ -190,6 +214,69 @@ protected virtual List OnReadFile(ExcelWorkbook workbook)
return sheets;
}
+ ///
+ /// Parses a CSV file and returns all of the data within the sheet.
+ ///
+ protected virtual IList OnReadCsv(Stream stream, ISheetModel model, IFormatProvider formatProvider)
+ {
+ using var parser = new CsvTextFieldParser(stream);
+
+ parser.Delimiters = new string[] { "," };
+ parser.HasFieldsEnclosedInQuotes = true;
+
+ var headerRow = 0;
+ var currentRow = 0;
+ string[] headers = null;
+ while (!parser.EndOfData) {
+ if (currentRow == headerRow) {
+ headers = parser.ReadFields();
+ ++currentRow;
+ break;
+ }
+ ++currentRow;
+ }
+
+ IList data = CreateListForSheet(model.Type, 0);
+ var columnMapping = new IColumnModel[model.Columns.Count];
+ var columnMapped = new bool[model.Columns.Count];
+ if (headers != null) {
+ var modelColumns = model.Columns.ToList();
+
+ for (int colIndex = 0; colIndex < headers.Length; colIndex++) {
+ var cell = headers[colIndex];
+ if (cell != null) {
+ var headerName = cell;
+ if (model.Columns.TryGetValue(headerName, out var columnModel)) {
+ var columnModelIndex = modelColumns.IndexOf(columnModel);
+ if (columnMapped[columnModelIndex])
+ throw new DuplicateColumnException(columnModel.Name, model.Name);
+ columnMapped[columnModelIndex] = true;
+ columnMapping[colIndex] = columnModel;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < model.Columns.Count; i++) {
+ if (columnMapped[i] == false && !model.Columns[i].Optional)
+ throw new ColumnMissingException(model.Columns[i].Name, model.Name);
+ }
+
+ while (!parser.EndOfData) {
+ var range = parser.ReadFields();
+ if (range.Length != columnMapping.Length) {
+ Array.Resize(ref range, columnMapping.Length);
+ }
+ var obj = OnReadCSVRow(range, model, columnMapping, formatProvider);
+ if (obj != null)
+ data.Add(obj);
+ ++currentRow;
+ }
+
+
+ return data;
+ }
+
///
/// Reads a worksheet and returns a set of of the entries.
///
@@ -248,6 +335,63 @@ protected virtual IList OnReadSheet(ExcelWorksheet worksheet, ISheetModel model)
return data;
}
+ protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumnModel[] columnMapping, IFormatProvider formatProvider)
+ {
+ if (range == null)
+ throw new ArgumentNullException(nameof(range));
+ if (model == null)
+ throw new ArgumentNullException(nameof(range));
+ if (columnMapping == null)
+ throw new ArgumentNullException(nameof(columnMapping));
+ var firstCol = 0;
+ var columns = range.Length;
+ //if (range.Rows != 1)
+ // throw new ArgumentOutOfRangeException(nameof(range), "Range must represent a single row of data");
+ if (columns != columnMapping.Length)
+ throw new ArgumentOutOfRangeException(nameof(columnMapping), "Number of columns in range does not match size of columnMapping array");
+ var obj = Activator.CreateInstance(model.Type);
+ if (range.Any(x => x != null)) {
+ for (int colIndex = 0; colIndex < columns; colIndex++) {
+ var col = colIndex + firstCol;
+ var columnModel = columnMapping[colIndex];
+ if (columnModel != null) {
+ var cell = range[col]; // note that range[] resets range.Address to equal the new address
+ if (string.IsNullOrEmpty(cell)) {
+ if (!columnModel.Optional)
+ throw new ColumnDataMissingException(columnModel.Name, model.Name);
+ } else {
+ object value;
+ try {
+ //if (columnModel.ReadSerializer != null) {
+ // value = columnModel.ReadSerializer(cell);
+ //} else {
+ value = DefaultCsvReadSerializer(cell, cell, columnModel.Type, formatProvider);
+ //}
+ } catch (Exception e) {
+ throw new ParseDataException(cell, columnModel.Name, model.Name, e);
+ }
+ if (value != null) {
+ if (columnModel.Member is PropertyInfo propertyInfo) {
+ propertyInfo.SetMethod.Invoke(obj, new[] { value });
+ } else if (columnModel.Member is FieldInfo fieldInfo) {
+ fieldInfo.SetValue(obj, value);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ if (model.SkipEmptyRows) {
+ obj = null;
+ } else {
+ foreach (var columnModel in columnMapping) {
+ if (!columnModel.Optional)
+ throw new RowEmptyException(model.Name);
+ }
+ }
+ }
+ return obj;
+ }
///
/// Parses a row of data or returns null if the row should be skipped
///
@@ -324,6 +468,90 @@ protected virtual ExcelRange DefaultReadRangeLocator(ExcelWorksheet worksheet)
return worksheet.Cells[dimension.Start.Row, dimension.Start.Column, dimension.End.Row, dimension.End.Column];
}
+ protected virtual object DefaultCsvReadSerializer(object value, string text, Type dataType, IFormatProvider formatProvider)
+ {
+ if (value == null) {
+ return null;
+ }
+ if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
+ return DefaultCsvReadSerializer(value, text, Nullable.GetUnderlyingType(dataType), formatProvider);
+ }
+ if (value.GetType() == dataType)
+ return value;
+ if (dataType == typeof(string))
+ return text;
+ if (dataType == typeof(DateTime)) {
+ if (value is string str)
+ return DateTime.Parse(str, formatProvider, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal);
+ return DateTime.FromOADate((double)DefaultCsvReadSerializer(value, text, typeof(double), formatProvider));
+ }
+ if (dataType == typeof(TimeSpan)) {
+ if (value is DateTime dt)
+ return dt.TimeOfDay;
+ if (value is string str)
+ try {
+ return TimeSpan.Parse(str, formatProvider);
+ } catch (FormatException) {
+ return DateTime.Parse(str, formatProvider, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal).TimeOfDay;
+ }
+ }
+ if (dataType == typeof(DateTimeOffset)) {
+ throw new NotSupportedException("DateTimeOffset values are not supported");
+ }
+ if (dataType == typeof(Uri)) {
+ return new Uri(text);
+ }
+ if (dataType == typeof(Guid)) {
+ return Guid.Parse(text);
+ }
+ if (dataType == typeof(bool)) {
+ if (value is string str) {
+ switch (str.ToLower()) {
+ case "y":
+ case "1":
+ case "yes":
+ case "true":
+ return true;
+ case "n":
+ case "0":
+ case "no":
+ case "false":
+ return false;
+ }
+ }
+ }
+
+ if (dataType == typeof(int)) {
+ if (value is string str) {
+ var success = int.TryParse(str, NumberStyles.Any, formatProvider, out int result);
+ if (success)
+ return result;
+
+ return Convert.ToInt32(Math.Floor(double.Parse(str, NumberStyles.Any, formatProvider)));
+ }
+ }
+
+ if (dataType == typeof(double)) {
+ if (value is string str) {
+ return double.Parse(str, NumberStyles.Any, formatProvider);
+ }
+ }
+
+ if (dataType == typeof(decimal)) {
+ if (value is string str) {
+ return decimal.Parse(str, NumberStyles.Any, formatProvider);
+ }
+ }
+
+ if (dataType == typeof(float)) {
+ if (value is string str) {
+ return float.Parse(str, NumberStyles.Any, formatProvider);
+ }
+ }
+
+ return Convert.ChangeType(value, dataType);
+ }
+
///
/// Parses the cell and converts it to the requested data type. For nullable types,
/// it is acceptable to return the underlying type.
diff --git a/src/Shane32.ExcelLinq/Models/CsvRange.cs b/src/Shane32.ExcelLinq/Models/CsvRange.cs
new file mode 100644
index 0000000..32cea08
--- /dev/null
+++ b/src/Shane32.ExcelLinq/Models/CsvRange.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Shane32.ExcelLinq.Models
+{
+ public class CsvRange
+ {
+ public int StartColumn { get; set; }
+ public int StartRow { get; set; }
+ public int? EndColumn { get; set; }
+ public int? EndRow { get; set; }
+ }
+}
diff --git a/src/Shane32.ExcelLinq/Models/IExcelModel.cs b/src/Shane32.ExcelLinq/Models/IExcelModel.cs
index ac7b6fe..270f0dc 100644
--- a/src/Shane32.ExcelLinq/Models/IExcelModel.cs
+++ b/src/Shane32.ExcelLinq/Models/IExcelModel.cs
@@ -4,5 +4,6 @@ public interface IExcelModel
{
ISheetModelLookup Sheets { get; }
bool IgnoreSheetNames { get; }
+ bool ReadCsv { get; }
}
}
diff --git a/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj b/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj
index 0d23902..1d6944c 100644
--- a/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj
+++ b/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj
@@ -7,6 +7,7 @@
+