mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-12-02 03:47:41 +08:00
0.2.2
- SavaAs support xl/sheet dimension - [Breaking Changes] SaveAs value type from object to DataTable & ICollection - Bug fix: ICollection with type but no data error (https://github.com/shps951023/MiniExcel/issues/105)
This commit is contained in:
parent
1d33ccdce8
commit
786e2a82bd
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
|
### 0.2.2
|
||||||
|
- SavaAs support xl/sheet dimension
|
||||||
|
- [Breaking Changes] SaveAs value type from object to DataTable & ICollection
|
||||||
|
- Bug fix: ICollection with type but no data error (https://github.com/shps951023/MiniExcel/issues/105)
|
||||||
|
|
||||||
### 0.2.1
|
### 0.2.1
|
||||||
- Optimize type mapping bool and datetime auto check
|
- Optimize type mapping bool and datetime auto check
|
||||||
- Query Support xl/worksheets/Sheet Xml Xml `<c>` without `r` attribute or without `<dimension>` but `<c>` with `r` attribute, but now performance is slow than with dimension ([](https://github.com/shps951023/MiniExcel/issues/2))
|
- Query Support xl/worksheets/Sheet Xml Xml `<c>` without `r` attribute or without `<dimension>` but `<c>` with `r` attribute, but now performance is slow than with dimension ([](https://github.com/shps951023/MiniExcel/issues/2))
|
||||||
|
108
drafts/【Reflection】Get ICollection Generic Type.linq
Normal file
108
drafts/【Reflection】Get ICollection Generic Type.linq
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<Query Kind="Program">
|
||||||
|
<Connection>
|
||||||
|
<ID>5fffb9dc-a56f-4ffa-a582-f9da6bc9fdad</ID>
|
||||||
|
<Persist>true</Persist>
|
||||||
|
<Server>192.168.1.4</Server>
|
||||||
|
<SqlSecurity>true</SqlSecurity>
|
||||||
|
<UserName>sa</UserName>
|
||||||
|
<Password>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAyumoRWrbXEqda8ynsoawYAAAAAACAAAAAAAQZgAAAAEAACAAAACumZoBhp4lj0R4mTg98suX0pykwksNIARbRIh49xu5/QAAAAAOgAAAAAIAACAAAADoNABocqodkXYmDtdW0GqBvGuMfAJeL++I3kdCYqM4rxAAAADANn2PCQ6OByhczsa8iMQPQAAAAKx4dlXxPcHN4uDHZRcYbnhkQZ52tjk6YEm+q+GruBVhVPrtz22hjCT4VMaK2N6EtZF2Rfr2P8fUTQH/ZPns5GA=</Password>
|
||||||
|
<Database>kn2015</Database>
|
||||||
|
</Connection>
|
||||||
|
<NuGetReference>Dapper</NuGetReference>
|
||||||
|
<NuGetReference>MiniExcel</NuGetReference>
|
||||||
|
<NuGetReference>System.Data.SqlClient</NuGetReference>
|
||||||
|
<Namespace>Xunit</Namespace>
|
||||||
|
<RemoveNamespace>System.Data</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Diagnostics</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.IO</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Linq.Expressions</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Text</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Text.RegularExpressions</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Threading</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Transactions</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Xml</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Xml.Linq</RemoveNamespace>
|
||||||
|
<RemoveNamespace>System.Xml.XPath</RemoveNamespace>
|
||||||
|
</Query>
|
||||||
|
|
||||||
|
//[c# Reflection - Find the Generic Type of a Collection - Stack Overflow](https://stackoverflow.com/questions/2561070/c-sharp-reflection-find-the-generic-type-of-a-collection)
|
||||||
|
#load "xunit"
|
||||||
|
|
||||||
|
#region private::Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
void ValueGenericTypeTest()
|
||||||
|
{
|
||||||
|
var strings = new List<int>();
|
||||||
|
var props = Helpers.GetSubtypeGetProperties(strings);
|
||||||
|
Assert.Equal(0,props.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestType
|
||||||
|
{
|
||||||
|
public string A { get; set; }
|
||||||
|
public string B { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact()]
|
||||||
|
void IListUpcastingTest()
|
||||||
|
{
|
||||||
|
IList datas = new List<TestType>();
|
||||||
|
var props = Helpers.GetSubtypeGetProperties(datas).ToList();
|
||||||
|
Assert.Equal(2, props.Count());
|
||||||
|
Assert.Equal("A", props[0].Name);
|
||||||
|
Assert.Equal("B", props[1].Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact()]
|
||||||
|
void ArrayTest()
|
||||||
|
{
|
||||||
|
ICollection datas = new[] { new { A = "1", B = "2" } };
|
||||||
|
var props = Helpers.GetSubtypeGetProperties(datas);
|
||||||
|
Assert.Equal(2, props.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact()]
|
||||||
|
void OnlyValidOGenericTypes_Test()
|
||||||
|
{
|
||||||
|
ICollection datas = new[] { new { A = "1", B = "2" } };
|
||||||
|
var df = datas.GetType().GetGenericTypeDefinition(); //InvalidOperationException: This operation is only valid on generic types.
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact()]
|
||||||
|
void DictionaryTest()
|
||||||
|
{
|
||||||
|
ICollection datas = new[] { new Dictionary<string, object>() { { "A", "A" }, { "B", "B" } } };
|
||||||
|
var props = Helpers.GetSubtypeGetProperties(datas);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal static class Helpers
|
||||||
|
{
|
||||||
|
public static PropertyInfo[] GetSubtypeGetProperties(ICollection value)
|
||||||
|
{
|
||||||
|
var collectionType = value.GetType();
|
||||||
|
|
||||||
|
Type gType;
|
||||||
|
if (collectionType.IsGenericTypeDefinition || collectionType.IsGenericType)
|
||||||
|
gType = collectionType.GetGenericArguments().Single();
|
||||||
|
else if (collectionType.IsArray)
|
||||||
|
gType = collectionType.GetElementType();
|
||||||
|
else
|
||||||
|
throw new NotImplementedException($"{collectionType.Name} type not implemented,please issue for me, https://github.com/shps951023/MiniExcel/issues");
|
||||||
|
if (typeof(IDictionary).IsAssignableFrom(gType))
|
||||||
|
throw new NotImplementedException($"{gType.Name} type not implemented,please issue for me, https://github.com/shps951023/MiniExcel/issues");
|
||||||
|
var props = gType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Main()
|
||||||
|
{
|
||||||
|
//RunTests(); // Call RunTests() or press Alt+Shift+T to initiate testing.
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can define other methods, fields, classes and namespaces here
|
||||||
|
|
@ -12,6 +12,7 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using MiniExcelLibs.Utils;
|
using MiniExcelLibs.Utils;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
public static partial class MiniExcel
|
public static partial class MiniExcel
|
||||||
{
|
{
|
||||||
@ -26,13 +27,24 @@
|
|||||||
|
|
||||||
private readonly static UTF8Encoding Utf8WithBom = new System.Text.UTF8Encoding(true);
|
private readonly static UTF8Encoding Utf8WithBom = new System.Text.UTF8Encoding(true);
|
||||||
|
|
||||||
public static void SaveAs(this Stream stream,object value, string startCell = "A1", bool printHeader = true)
|
public static void SaveAs(this Stream stream, DataTable value, string startCell = "A1", bool printHeader = true)
|
||||||
{
|
{
|
||||||
SaveAsImpl(stream,GetCreateXlsxInfos(value, startCell, printHeader));
|
SaveAsImpl(stream, GetCreateXlsxInfos(value, startCell, printHeader));
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveAs(string filePath, object value, string startCell = "A1", bool printHeader = true)
|
public static void SaveAs(this Stream stream, ICollection value, string startCell = "A1", bool printHeader = true)
|
||||||
|
{
|
||||||
|
SaveAsImpl(stream, GetCreateXlsxInfos(value, startCell, printHeader));
|
||||||
|
stream.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveAs(string filePath, DataTable value, string startCell = "A1", bool printHeader = true)
|
||||||
|
{
|
||||||
|
SaveAsImpl(filePath, GetCreateXlsxInfos(value, startCell, printHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveAs(string filePath, ICollection value, string startCell = "A1", bool printHeader = true)
|
||||||
{
|
{
|
||||||
SaveAsImpl(filePath, GetCreateXlsxInfos(value, startCell, printHeader));
|
SaveAsImpl(filePath, GetCreateXlsxInfos(value, startCell, printHeader));
|
||||||
}
|
}
|
||||||
@ -42,7 +54,12 @@
|
|||||||
var xy = ExcelOpenXmlUtils.ConvertCellToXY(startCell);
|
var xy = ExcelOpenXmlUtils.ConvertCellToXY(startCell);
|
||||||
|
|
||||||
var defaultFiles = GetDefaultFiles();
|
var defaultFiles = GetDefaultFiles();
|
||||||
var dimensionRef = string.Empty;
|
|
||||||
|
// dimension
|
||||||
|
var dimensionRef = "A1";
|
||||||
|
var maxRowIndex = 0;
|
||||||
|
var maxColumnIndex = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
@ -52,17 +69,10 @@
|
|||||||
{
|
{
|
||||||
var dt = value as DataTable;
|
var dt = value as DataTable;
|
||||||
|
|
||||||
var maxRowIndex = dt.Rows.Count;
|
|
||||||
var maxColumnIndex = dt.Columns.Count;
|
|
||||||
// dimension
|
// dimension
|
||||||
{
|
maxRowIndex = dt.Rows.Count;
|
||||||
if (maxRowIndex == 0 && maxColumnIndex == 0)
|
maxColumnIndex = dt.Columns.Count;
|
||||||
dimensionRef = "A1";
|
|
||||||
else if ( maxColumnIndex == 1)
|
|
||||||
dimensionRef = $"A{maxRowIndex}";
|
|
||||||
else
|
|
||||||
dimensionRef = $"A1:{Helpers.GetAlphabetColumnName(maxColumnIndex-1)}{maxRowIndex}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printHeader)
|
if (printHeader)
|
||||||
{
|
{
|
||||||
@ -119,16 +129,12 @@
|
|||||||
else if (value is System.Collections.ICollection)
|
else if (value is System.Collections.ICollection)
|
||||||
{
|
{
|
||||||
var collection = value as System.Collections.ICollection;
|
var collection = value as System.Collections.ICollection;
|
||||||
object firstValue = null;
|
|
||||||
{
|
var props = Helpers.GetSubtypeProperties(collection);
|
||||||
foreach (var v in collection)
|
maxColumnIndex = props.Length;
|
||||||
{
|
if (props.Length == 0)
|
||||||
firstValue = v;
|
throw new InvalidOperationException($"Properties count is 0");
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var type = firstValue.GetType();
|
|
||||||
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
|
||||||
if (printHeader)
|
if (printHeader)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"<x:row r=\"{yIndex.ToString()}\">");
|
sb.AppendLine($"<x:row r=\"{yIndex.ToString()}\">");
|
||||||
@ -179,6 +185,17 @@
|
|||||||
sb.AppendLine($"</x:row>");
|
sb.AppendLine($"</x:row>");
|
||||||
yIndex++;
|
yIndex++;
|
||||||
}
|
}
|
||||||
|
maxRowIndex = yIndex-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dimension
|
||||||
|
{
|
||||||
|
if (maxRowIndex == 0 && maxColumnIndex == 0)
|
||||||
|
dimensionRef = "A1";
|
||||||
|
else if (maxColumnIndex == 1)
|
||||||
|
dimensionRef = $"A{maxRowIndex}";
|
||||||
|
else
|
||||||
|
dimensionRef = $"A1:{Helpers.GetAlphabetColumnName(maxColumnIndex - 1)}{maxRowIndex}";
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultFiles[@"xl/worksheets/sheet1.xml"].Xml = $@"<?xml version=""1.0"" encoding=""utf-8""?>
|
defaultFiles[@"xl/worksheets/sheet1.xml"].Xml = $@"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||||
@ -191,7 +208,7 @@
|
|||||||
return defaultFiles;
|
return defaultFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<T> Query<T>(this Stream stream) where T : class , new()
|
public static IEnumerable<T> Query<T>(this Stream stream) where T : class, new()
|
||||||
{
|
{
|
||||||
return QueryImpl<T>(stream);
|
return QueryImpl<T>(stream);
|
||||||
}
|
}
|
||||||
@ -294,10 +311,10 @@
|
|||||||
private static void SaveAsImpl(string path, Dictionary<string, ZipPackageInfo> zipPackageInfos)
|
private static void SaveAsImpl(string path, Dictionary<string, ZipPackageInfo> zipPackageInfos)
|
||||||
{
|
{
|
||||||
using (FileStream stream = new FileStream(path, FileMode.CreateNew))
|
using (FileStream stream = new FileStream(path, FileMode.CreateNew))
|
||||||
using(ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create, false, Utf8WithBom))
|
using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create, false, Utf8WithBom))
|
||||||
CreteXlsxImpl(zipPackageInfos, archive);
|
CreteXlsxImpl(zipPackageInfos, archive);
|
||||||
}
|
}
|
||||||
private static void SaveAsImpl(Stream stream,Dictionary<string, ZipPackageInfo> zipPackageInfos)
|
private static void SaveAsImpl(Stream stream, Dictionary<string, ZipPackageInfo> zipPackageInfos)
|
||||||
{
|
{
|
||||||
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true, Utf8WithBom))
|
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true, Utf8WithBom))
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<Product>MiniExcel</Product>
|
<Product>MiniExcel</Product>
|
||||||
<PackageTags>excel;xlsx;micro-helper;mini;openxml;helper;</PackageTags>
|
<PackageTags>excel;xlsx;micro-helper;mini;openxml;helper;</PackageTags>
|
||||||
<Description>
|
<Description>
|
||||||
A high performance Excel Xlsx Micro-Helper without any third party library and supporting create and dynamic/type mapping query etc..
|
A high performance Excel Xlsx Micro-Helper without any third party library to create and dynamic/type mapping query etc..
|
||||||
|
|
||||||
Github : https://github.com/shps951023/MiniExcel
|
Github : https://github.com/shps951023/MiniExcel
|
||||||
Issues : https://github.com/shps951023/MiniExcel/issues
|
Issues : https://github.com/shps951023/MiniExcel/issues
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<RepositoryUrl>https://github.com/shps951023/MiniExcel</RepositoryUrl>
|
<RepositoryUrl>https://github.com/shps951023/MiniExcel</RepositoryUrl>
|
||||||
<PackageIconUrl>https://raw.githubusercontent.com/shps951023/ImageHosting/master/img/2019-01-17.13.18.32-image.png</PackageIconUrl>
|
<PackageIconUrl>https://raw.githubusercontent.com/shps951023/ImageHosting/master/img/2019-01-17.13.18.32-image.png</PackageIconUrl>
|
||||||
<TargetFrameworks>net461;netstandard2.0;net5.0</TargetFrameworks>
|
<TargetFrameworks>net461;netstandard2.0;net5.0</TargetFrameworks>
|
||||||
<Version>0.2.1</Version>
|
<Version>0.2.2</Version>
|
||||||
<PackageReleaseNotes>Please Check [Release Notes](https://github.com/shps951023/MiniExcel/tree/master/docs)</PackageReleaseNotes>
|
<PackageReleaseNotes>Please Check [Release Notes](https://github.com/shps951023/MiniExcel/tree/master/docs)</PackageReleaseNotes>
|
||||||
<RepositoryType>Github</RepositoryType>
|
<RepositoryType>Github</RepositoryType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace MiniExcelLibs.Utils
|
namespace MiniExcelLibs.Utils
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@ -64,13 +65,29 @@ namespace MiniExcelLibs.Utils
|
|||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<PropertyInfo> GetPropertiesWithSetter(Type type)
|
public static IEnumerable<PropertyInfo> GetPropertiesWithSetter(this Type type)
|
||||||
{
|
{
|
||||||
return type.GetProperties(BindingFlags.SetProperty |
|
return type.GetProperties(BindingFlags.SetProperty |
|
||||||
BindingFlags.Public |
|
BindingFlags.Public |
|
||||||
BindingFlags.Instance).Where(prop => prop.GetSetMethod() != null);
|
BindingFlags.Instance).Where(prop => prop.GetSetMethod() != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PropertyInfo[] GetSubtypeProperties(ICollection value)
|
||||||
|
{
|
||||||
|
var collectionType = value.GetType();
|
||||||
|
|
||||||
|
Type gType;
|
||||||
|
if (collectionType.IsGenericTypeDefinition || collectionType.IsGenericType)
|
||||||
|
gType = collectionType.GetGenericArguments().Single();
|
||||||
|
else if (collectionType.IsArray)
|
||||||
|
gType = collectionType.GetElementType();
|
||||||
|
else
|
||||||
|
throw new NotImplementedException($"{collectionType.Name} type not implemented,please issue for me, https://github.com/shps951023/MiniExcel/issues");
|
||||||
|
if (typeof(IDictionary).IsAssignableFrom(gType))
|
||||||
|
throw new NotImplementedException($"{gType.Name} type not implemented,please issue for me, https://github.com/shps951023/MiniExcel/issues");
|
||||||
|
var props = gType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
public static string ConvertEscapeChars(string input)
|
public static string ConvertEscapeChars(string input)
|
||||||
{
|
{
|
||||||
|
@ -270,6 +270,48 @@ namespace MiniExcelLibs.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SaveAsFileWithDimensionByICollectionTestType
|
||||||
|
{
|
||||||
|
public string A { get; set; }
|
||||||
|
public string B { get; set; }
|
||||||
|
}
|
||||||
|
[Fact()]
|
||||||
|
public void SaveAsFileWithDimensionByICollection()
|
||||||
|
{
|
||||||
|
//List<strongtype>
|
||||||
|
{
|
||||||
|
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||||
|
var values = new List<SaveAsFileWithDimensionByICollectionTestType>()
|
||||||
|
{
|
||||||
|
new SaveAsFileWithDimensionByICollectionTestType{A="A",B="B"},
|
||||||
|
new SaveAsFileWithDimensionByICollectionTestType{A="A",B="B"},
|
||||||
|
};
|
||||||
|
MiniExcel.SaveAs(path, values);
|
||||||
|
Assert.Equal("A1:B3", GetFirstSheetDimensionRefValue(path));
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Array<anoymous>
|
||||||
|
{
|
||||||
|
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||||
|
var values = new []
|
||||||
|
{
|
||||||
|
new {A="A",B="B"},
|
||||||
|
new {A="A",B="B"},
|
||||||
|
};
|
||||||
|
MiniExcel.SaveAs(path, values);
|
||||||
|
Assert.Equal("A1:B3", GetFirstSheetDimensionRefValue(path));
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// without properties
|
||||||
|
{
|
||||||
|
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||||
|
var values = new List<int>();
|
||||||
|
Assert.Throws<InvalidOperationException>(() => MiniExcel.SaveAs(path, values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact()]
|
[Fact()]
|
||||||
public void SaveAsFileWithDimension()
|
public void SaveAsFileWithDimension()
|
||||||
{
|
{
|
||||||
@ -368,6 +410,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
{
|
{
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||||
|
|
||||||
var table = new DataTable();
|
var table = new DataTable();
|
||||||
{
|
{
|
||||||
table.Columns.Add("a", typeof(string));
|
table.Columns.Add("a", typeof(string));
|
||||||
|
Loading…
Reference in New Issue
Block a user