【发布时间】:2011-03-03 23:43:06
【问题描述】:
总结
这个问题在某种程度上是这个问题的后续:
How to implement column self-naming from its index?
在测试了上面链接的问题答案中提供的代码后,我终于遇到了一个严重的性能问题。
性能问题
性能问题发生在 Sheet 初始化时,即当我初始化 Sheet 的单元格时。
''' <summary>
''' Initialize an instance of the Company.Project.Sheet class.
''' </summary>
''' <param name="nativeSheet">The native worksheet from which to initialize.</param>
Friend Sub New(ByVal nativeSheet As Microsoft.Office.Interop.Excel.Worksheet)
_nativeSheet = nativeSheet
Dim cells As IDictionary(Of String, ICell) = New Dictionary(Of String, ICell)()
'These iterations hurt the performance of the API...'
For rowIndex As Integer = 1 To _nativeSheet.Rows.Count Step 1
For colIndex As Integer = 1 To _nativeSheet.Columns.Count Step 1
Dim c As ICell = New Cell(_nativeSheet.Cells(rowIndex, colIndex))
cellules.Add(c.Name, c)
Next
Next
_cellules = New ReadOnlyDictionary(Of String, ICell)(cells)
End Sub
- ReadOnlyDictionary(Of TKey, TValue) :
A custom read-only dictionary that simply wraps a IDictionary(Of TKey, TValue) to prevent modifications.讨论
我之所以这样工作,是因为底层电子表格工作表中的每个单元格都是从工作表的初始化开始到最后进行初始化的,也就是说,当工作表被处置或完成时。因此,我希望以同样的方式初始化工作表的单元格,但我也希望保持在命名(“A1”)单元格上使用索引单元格的性能提升,同时保持 API 用户的易用性引用具有其名称的单元格,这就是我打算使用字典的方式,因此当我引用单元格“A1”时,我将这个键访问到我的字典中并相应地寻址单元格 (1, 1)。
除此之外,我还知道一种使用 Worksheet.UsedRange 属性从工作表中读取数据的更快方法,该属性将所有使用过的单元格返回到 2D 矩阵中。
如果对于我可以用来初始化我的 Cell 类的多个实例的单元集有任何相同或大致相同,那将是非常棒的,而且性能很好!我还想过在内存中初始化一个 100 x 100 的矩阵单元,同时将它们映射到我的字典,因为很少会使用整个工作表的单元。因此,我仍在考虑一种必须访问尚未初始化的单元格的方法,比如 Cells(120, 120)。理想情况下,我认为,程序必须初始化最大初始初始化 Cell(100, 100) 到 Cell (120, 120) 之间的所有单元格。我在这里够清楚吗?随时要求澄清! =)
-
另一种选择可能是我只将单元格的名称初始化到字典中并将行和列索引保留在内存中,而不是使用其 nativeCell 初始化 Cell 实例,例如 Range。这是我的 Cell 类的代码来说明我的意思。
''' ''' 表示工作表中的一个单元格。 ''' ''' 朋友类细胞 实现 ICell
Private _nativeCell As Microsoft.Office.Interop.Excel.Range Private _name As String ''' <summary> ''' Initializes a new instance of the Company.Project.Cell class. ''' </summary> ''' <param name="nativeCell">The Microsoft.Office.Interop.Excel.Range to wrap.</param> Friend Sub New(ByVal nativeCell As Microsoft.Office.Interop.Excel.Range) _nativeCell = nativeCell End Sub Public ReadOnly Property NativeCell() As Microsoft.Office.Interop.Excel.Range Implements ICellule.NativeCell Get Return _nativeCell End Get End Property Public ReadOnly Property Column() As Integer Implements ICell.Column Get Return _nativeCell.Column End Get End Property Public ReadOnly Property Row() As Integer Implements ICell.Row Get Return _nativeCell.Row End Get End Property Public ReadOnly Property Name() As String Implements ICellule.Name Get If (String.IsNullOrEmpty(_name) OrElse _name.Trim().Length = 0) Then _ _name = GetColumnName() Return _nom End Get End Property Public Property Value() As Object Implements ICellule.Value Get Return _nativeCell.Value2 End Get Set(ByVal value As Object) _nativeCell.Value2 = value End Set End Property Public ReadOnly Property FormattedValue() As String Implements ICellule.FormattedValue Get Return _nativeCell.Text End Get End Property Public ReadOnly Property NumericValue() As Double? Implements ICellule.NumericValue Get Return Value End Get End Property
问题
我还有哪些其他选择?
还有其他方法可以通过吗?
有没有一种方法可以使实际方法在性能问题上可行?
供您参考,此问题在测试时超时,因此测试从未在实际上需要几个世纪的可接受时间范围内结束......
欢迎任何想法!我对其他解决方案或方法持开放态度,这些解决方案或方法将帮助我在解决此性能问题的同时实现此目标。
谢谢大家! =)
编辑#1
感谢Maxim Gueivandov,他的解决方案解决了我在这个问题中解决的问题。
除此之外,此解决方案还引发了另一个问题:SystemOutOfMemoryException,这将在另一个问题中解决。
向马克西姆·盖万多夫致以最诚挚的谢意。
【问题讨论】:
标签: .net performance excel office-interop