.net 在允许我实例化工作表的单元格时,使用什么体系结构来解决SystemOutOfMemoryException?
摘要 这个问题是对一个愿望的后续,即设计一个简单的电子表格API,同时使它对熟悉Excel的人保持用户友好 总之,这个问题与以下两个问题有关:.net 在允许我实例化工作表的单元格时,使用什么体系结构来解决SystemOutOfMemoryException?,.net,vb.net,performance,excel,interop,.net,Vb.net,Performance,Excel,Interop,摘要 这个问题是对一个愿望的后续,即设计一个简单的电子表格API,同时使它对熟悉Excel的人保持用户友好 总之,这个问题与以下两个问题有关: 1. ; 2. . 目标 提供一个简化的Excel API,用作Nevragic组件(如应用程序、工作簿、工作表和范围类/接口)的包装器,同时仅公开这些组件中最常用的对象属性 用法示例 这个使用示例的灵感来自单元测试,单元测试使我能够将这个解决方案提升到现在的水平 Dim file as String = "C:\Temp\WriteTest.xls"
1. ;
2. . 目标 提供一个简化的Excel API,用作Nevragic组件(如
应用程序
、工作簿
、工作表
和范围
类/接口)的包装器,同时仅公开这些组件中最常用的对象属性
用法示例
这个使用示例的灵感来自单元测试,单元测试使我能够将这个解决方案提升到现在的水平
Dim file as String = "C:\Temp\WriteTest.xls"
Using mgr As ISpreadsheetManager = New SpreadsheetManager()
Dim wb as IWorkbook = mgr.CreateWorkbook()
wb.Sheets("Sheet1").Cells("A1").Value = 3.1415926
wb.SaveAs(file)
End Using
现在我们打开它:
Dim file as String = "C:\Temp\WriteTest.xls"
Using mgr As ISpreadsheetManager = New SpreadsheetManager()
Dim wb as IWorkbook = mgr.OpenWorkbook(file)
// Working with workbook here...
End Using
讨论
实例化Excel工作簿时:
范围
对象初始化其单元格范围
李>
ICell
界面交付最常用的属性李>
区域
单元格Range.Value
属性是使用互操作与底层Excel应用程序实例进行交互的最快方式
因此,我想用单元格的名称初始化我的readonlydictionary(of String,ICell)
,而不立即包装Range
接口的实例,这样我就可以简单地生成行和列索引以及单元格的名称来索引我的字典,然后,仅当需要访问或格式化特定单元格或单元格区域时,才分配Cell.NativeCell
属性
这样,字典中的数据将使用从工作表
类构造函数中生成的列索引中获得的单元格名称进行索引。那么,当我们这样做的时候:
Using mgr As ISpreadsheetManager = New SpreadsheetManager()
Dim wb As IWorkbook = mgr.CreateWorkbook()
wb.Sheet(1).Cells("A1").Value = 3.1415926 // #1:
End Using
#1:这将允许我使用单元格
类中的索引将给定值写入特定单元格,这比直接针对范围使用其名称更快
问题和顾虑
此外,当使用UsedRange.get_Value()
或单元格.get_Value()
时,将返回对象(,)数组
1。因此,我是否应该只满足于使用单元格的对象(,)
数组,而不必以某种方式格式化它?
2。如何构建这些工作表和单元格类,以便在使用对象(,)
数组时获得最佳性能,同时保持单元格实例可能表示或包装单个单元格范围的可能性?
感谢你们中任何一位花时间阅读我的文章的人,我最真诚的感谢那些回答我的人
所使用的体系结构经历了一个我命名为CellCollection
的对象类。它的作用如下:
基于这些假设:
假设Excel工作表有256列和65536行
假设一次需要实例化16777216(256*65536)个单元
考虑到工作表最常见的使用少于1000行,少于100列
考虑到我需要它能够引用带有地址的单元格(“A1”);和
根据基准测试,一次访问所有值并将其加载到内存中的对象[,]
,是处理底层Excel工作表的最快方法*
我考虑过不实例化任何单元格,让我的IWorksheet
接口中的CellCollection
属性在实例化时初始化并清空,现有工作簿除外。因此,在打开工作簿时,我会验证NativeSheet.UsedRange
是否为空或返回null(在Visual Basic中为空),否则,我已经在内存中获取了使用过的“本机单元格”,因此只剩下将它们添加到我的内部CellCollection
字典中,同时使用它们各自的地址对它们进行索引
最后,设计模式来营救!=)
公共课程表:ISHET{
公共工作表(Microsoft.Office.Interop.Excel.Worksheet nativeSheet){
NativeSheet=NativeSheet;
单元格=新的单元格集合(此);
}
public Microsoft.Office.Interop.Excel.Worksheet NativeSheet{get;private set;}
公共单元格集合单元格{get;private set;}
}
公开密封类别收集{
私有索引单元;
私人只读字典;
公共牢房收藏(ISHET表){
_单元格=新字典();
_readonlyCells=新的ReadonlyDictionary(_单元格);
板材=板材;
public class Sheet : ISheet {
public Worksheet(Microsoft.Office.Interop.Excel.Worksheet nativeSheet) {
NativeSheet = nativeSheet;
Cells = new CellCollection(this);
}
public Microsoft.Office.Interop.Excel.Worksheet NativeSheet { get; private set; }
public CellCollection Cells { get; private set; }
}
public sealed class CellCollection {
private IDictionary<string, ICell> _cells;
private ReadOnlyDictionary<string, ICell> _readonlyCells;
public CellCollection(ISheet sheet) {
_cells = new Dictionary<string, ICell>();
_readonlyCells = new ReadonlyDictionary<string, ICell>(_cells);
Sheet = sheet;
}
public readonly ReadOnlyDictionary<string, ICell> Cells(string addresses) {
get {
if (string.IsNullOrEmpty(addresses) || 0 = address.Trim().Length)
throw new ArgumentNullException("addresses");
if (!Regex.IsMatch(addresses, "(([A-Za-z]{1,2,3}[0-9]*)[:,]*)"))
throw new FormatException("addresses");
foreach(string address in addresses.Split(",") {
Microsoft.Office.Interop.Excel.Range range = Sheet.NativeSheet.Range(address)
foreach(Microsoft.Office.Interop.Excel.Range cell in range) {
ICell c = null;
if (!_cells.TryGetValue(cell.Address(false, false), c)) {
c = new Cell(cell);
_cells.Add(c.Name, c);
}
}
}
return _readonlyCells;
}
}
public readonly ISheet Sheet { get; private set; }
}