Wil*_*ler 7 .net vb.net excel performance interop
摘要
这个问题是建立一个简单的电子表格API的愿望的后续,同时保持对熟悉Excel的用户友好.
总结一下,这个问题与以下两个问题有关:
1.如何从索引实现列自命名?;
2. 如何使此自定义工作表初始化更快?.
目的
为了提供用作包装在nevralgic组件,如一个简化的Excel API Application,所述Workbook的Worksheet和Range同时暴露只为每个这些最常用的对象属性的类/接口.
用法示例
这个用法示例的灵感来自单元测试,使我能够将此解决方案带到现在的位置.
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
Run Code Online (Sandbox Code Playgroud)
现在我们打开它:
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
Run Code Online (Sandbox Code Playgroud)
讨论
在实例化Excel工作簿时:
Range可以表示一个或多个单元格的对象初始化其单元格.只要工作表存在,就可以立即访问这些单元格及其所有属性.
我的愿望是重现这种行为
我的问题来自Worksheet类构造函数,同时初始化#2中说明的Worksheet.Cells集合属性.
思考
在上述相关问题遇到问题后,我想找出另一种架构,让我能够:
Range在需要时访问单元的特定功能;ICell界面提供最常用的属性;Range从初始化访问工作表的所有单元格.同时请记住,Range.Value使用Interop 访问属性是与底层Excel应用程序实例可能的最快交互.
所以,我想初始化我的ReadonlyOnlyDictionary(Of String, ICell)与细胞的名称,而不是立即包裹的实例Range接口,这样我就简单地生成随着细胞的姓名索引我的字典里,然后行和列的索引,分配Cell.NativeCell,只有当一个属性想要访问或格式化特定的细胞或细胞范围.
这样,字典中的数据将使用从Worksheet类构造函数中生成的列索引获取的单元格的名称进行索引.然后,当一个人这样做:
Using mgr As ISpreadsheetManager = New SpreadsheetManager()
Dim wb As IWorkbook = mgr.CreateWorkbook()
wb.Sheet(1).Cells("A1").Value = 3.1415926 // #1:
End Using
Run Code Online (Sandbox Code Playgroud)
#1:这将允许我使用我的Cell类中的索引将给定值写入特定单元格,这比直接使用其名称更快Range.
问题和疑虑
此外,使用UsedRange.get_Value()或时Cells.get_Value(),它返回Object(,)数组.
那么我是否应该对使用Object(,)数组的数组感到满意,而不能以某种方式格式化它?
2.如何构建这些Worksheet和Cell类,以便在使用Object(,)数组时提供最佳性能,同时保持Cell实例可能表示或包装单个单元格Range的可能性?
感谢任何一个花时间阅读我的帖子的人,也感谢那些回答的人.
使用的体系结构已经经历了我命名为的对象类CellCollection。它的作用如下:
基于这些假设:
假设 Excel 工作表有 256 列和 65536 行;
假设一次需要实例化 16,777,216 (256 * 65536) 个单元;
鉴于工作表最常见的用途是少于 1,000 行和少于 100 列;
鉴于我需要它能够引用单元格及其地址(“A1”);和
鉴于一次性访问所有值并将其加载到
object[,]内存中的基准测试是使用基础 Excel 工作表的最快方法,*
我考虑过不实例化任何单元格,让界面CellCollection中的属性IWorksheet在实例化时初始化并清空,现有工作簿除外。因此,当打开工作簿时,我验证其NativeSheet.UsedRange为空或返回 null(在 Visual Basic 中为 Nothing),否则,我已经在内存中获取了使用的“本机单元格”,因此只需在索引它们时将它们添加到我的内部CellCollection字典中以及他们各自的地址。
最后,延迟初始化设计模式来救援!=)
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; }
}
Run Code Online (Sandbox Code Playgroud)
显然,这是第一次尝试,到目前为止效果还不错,性能超出了可接受的范围。谦虚地说,我觉得它可以使用一些优化,尽管我现在会这样使用它,并在需要时稍后进行优化。
写完这个集合后,我能够达到预期的行为。现在,我将尝试实现一些 .NET 接口,使其可用于某些IEnumerable、IEnumerable<T>、ICollection、ICollection<T>等,以便它可以分别被视为真正的 .NET 集合。
请随意评论并对此代码提出建设性的替代方案和/或更改,以便它可能变得比当前更强大。
我确实希望有一天这能达到目的。
谢谢阅读!=)
| 归档时间: |
|
| 查看次数: |
289 次 |
| 最近记录: |