2011-03-02 48 views
0

摘要如何使此自定義工作表初始化更快?

這個問題是某種跟進這個問題:
How to implement column self-naming from its index?

已經測試了這上面鏈接的問題的答案提供的代碼,我終於遇到了一個嚴重性能問題。一旦出現一個表初始化

性能問題

的性能問題,那就是,當我初始化表的單元格。

''' <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(中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物業的工作表來讀取。

    如果對於可以初始化我的Cell類的多個實例的一組單元格有任何相同或大致相同的情況,這將會很好,並且是高性能的!

  • 我也想過初始化時只能像內存中的100 x 100矩陣單元格一樣映射到我的字典中,因爲我們很少使用整個單元格的單元格。因此,我仍然想到一種方法,我必須訪問尚未初始化的單元格,讓我們說單元格(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. 我有什麼其他選擇?

  2. 還有其他方法可以通過嗎?

  3. 有沒有一種方法可以使實際方法成爲可行的性能問題?

爲了您的信息,這個問題超時的測試,所以測試從未實際上需要幾百年在可接受的時間範圍內結束...

有什麼想法,歡迎!我開放的意見是其他解決方案或方法,這將幫助我在解決此性能問題的同時實現此目標。

感謝大家! =)

編輯#1

由於Maxim Gueivandov,他的解決方案解決了我在這一問題已經解決了這個問題。

另外,這個解決方案還有另一個問題:SystemOutOfMemoryException,這個問題將在另一個問題中解決。

我的真誠感謝Maxim Gueivandov。

回答

1

你可以嘗試在一跳中獲取所用單元格範圍內的所有單元格,從而避免在每次迭代迭代時調用Cells(rowIndex, colIndex)(我猜Cells隱藏了可能會影響性能的互操作調用)。

Dim usedRange As Range = nativeSheet.UsedRange 
Dim cells(,) As Object = DirectCast(usedRange.get_Value(_ 
    XlRangeValueDataType.xlRangeValueDefault), Object(,)) 
[... do your row/col iterations ...] 

你會發現這是我基於下面的文章在這些假設的一些性能提示:C# Excel Interop Use。最值得注意的是,檢查基準部:

===在C#=== Excel的互操作基準

細胞[]:30.0秒

get_Range(),將細胞[]:15.0秒

UsedRange,的get_value():1.5秒 [最快]

+0

+1我絕對與你和你特此呈現基準一致。你說得對,'usedRange'是最快的方法。此外,我的願望是實例化所有工作表的單元格,儘管它們不被使用。例如,考慮一個新的空白工作表。單元雖然沒有被使用,但被實例化。拿單元格(200,200)來說,我不記得有沒有看過一個包含那麼多數據的Excel文件。雖然這個單元格沒有被使用,但它的範圍存在於內存中。這也是我所希望的。那麼,有沒有類似於'UsedRange'屬性來獲取所有單元格的方法? – 2011-03-03 01:04:27

+0

@ will:如何** [nativeSheet.Cells](http://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.worksheet.cells.aspx)**? – 2011-03-03 12:17:47

+0

'Worksheet.Cells'屬性返回一個'Range'對象實例,因此它不能像'Worksheet.UsedRange'那樣在'Object(,)'數組中被鑄造。除此之外,我想知道這種方法是否可行。我的架構思想是爲用戶提供Excel Interop API提供的所有靈活性,同時降低其複雜性,即從底層電子表格API抽象化。例如,我不會實現Range類中包含的所有屬性,例如,編碼最常用的屬性,如值,列,行,名稱。 – 2011-03-03 14:45:00