【问题标题】:Why do I have to convert ‘Cells’ here?为什么我必须在这里转换“单元格”?
【发布时间】:2021-09-07 18:11:38
【问题描述】:

简单的担忧:我注意到我必须在此处使用CType 进行转换,即使Cells 已经返回Range。我究竟做错了什么? Cells 是只读的,不带任何参数。好吧,我曾经被这样展示过。

如果我这样做

xlRange = myWorksheet.Cells(Line + 1US, 2US)

错误是

Option Strict On 不允许从 'Object' 到 'Range' 的隐式转换

我想提一下——如果是因为这个原因——我将 Option Infer Off 关闭,这样我就强迫自己总是写下类型。

源代码应将测量值写入 Excel 表中一段时间​​。

例子:

    A          B        C
1  07.09.2021  08:00    25,0
2              12:00    30,0
3              16:00    35,0
4  08.09.2021  08:00    26,0
5              12:00    28,0
6              16:00    26,0

类范围的变量:

Private Time_of_the_program_start As Date
Private Duration_of_the_runtime As TimeSpan
Private xlApp As Excel.Application
Private myWorkbook As Excel.Workbook
Private running As Boolean = False
Private Line As UInt16 = 0US
Private ReadOnly Deu As New System.Globalization.CultureInfo("de-DE")

running 在按钮过程中设置为 True。

Private Function read_and_write_data(ByVal file_path As String) As Boolean
        xlApp = New Excel.Application With {
            .Visible = True
        }
        myWorkbook = xlApp.Workbooks.Add()
        Dim myWorksheet As Excel.Worksheet = CType(myWorkbook.Sheets("Tabelle1"), Excel.Worksheet)
        Dim xlRange As Excel.Range
        Dim Temperatur As Single

        While running
            Duration_of_the_runtime = Date.Now - Time_of_the_program_start
            If Duration_of_the_runtime.Days = 365 Then Exit While

            Me.Invoke(Sub() Label_Duration.Text =
                          Duration_of_the_runtime.Days.ToString(Deu).PadLeft(3, "0"c) & ":" &
                          Duration_of_the_runtime.Hours.ToString(Deu).PadLeft(2, "0"c) & ":" &
                          Duration_of_the_runtime.Minutes.ToString(Deu).PadLeft(2, "0"c))

            'System.Threading.Thread.Sleep(10000)
            'myWorksheet.Cells(Line, column)
            '–––––––––––––––––––––––––––––––––––––––
            'Spalte A: Datum
            '–––––––––––––––––––––––––––––––––––––––
            xlRange = CType(myWorksheet.Cells(Line + 1US, 1US), Excel.Range)
            xlRange.Value = Date.Now.ToString("d", Deu)
            '–––––––––––––––––––––––––––––––––––––––
            'Spalte B: Uhrzeiten
            'Spalte C: Messwerte
            '–––––––––––––––––––––––––––––––––––––––
            Temperatur = Get_Temperature_from_Pt100()

            xlRange = CType(myWorksheet.Cells(Line + 1US, 2US), Excel.Range)
            xlRange.Value = Date.Now.ToString("t", Deu)

            xlRange = CType(myWorksheet.Cells(Line + 1US, 3US), Excel.Range)
            xlRange.Value = Temperatur
            '‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
            Temperatur = Get_Temperature_from_Pt100()
            xlRange = CType(myWorksheet.Cells(Line + 2US, 2US), Excel.Range)
            xlRange.Value = Date.Now.ToString("t", Deu)

            xlRange = CType(myWorksheet.Cells(Line + 2US, 3US), Excel.Range)
            xlRange.Value = Temperatur
            '‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
            Temperatur = Get_Temperature_from_Pt100()
            xlRange = CType(myWorksheet.Cells(Line + 3US, 2US), Excel.Range)
            xlRange.Value = Date.Now.ToString("t", Deu)

            xlRange = CType(myWorksheet.Cells(Line + 3US, 3US), Excel.Range)
            xlRange.Value = Temperatur
            '–––––––––––––––––––––––––––––––––––––––
            'inkrementieren
            '–––––––––––––––––––––––––––––––––––––––
            Line += 3US
        End While

        myWorksheet.SaveAs(file_path, Excel.XlFileFormat.xlWorkbookDefault)
        myWorkbook.Close()
        xlApp.Quit()
        If myWorksheet IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(myWorksheet)
        If myWorkbook IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(myWorkbook)
        If xlApp IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
        xlApp = Nothing
        myWorkbook = Nothing
        myWorksheet = Nothing

        Return True
    End Function

顺便问一下:有没有更优雅的解决方案?

Me.Invoke(Sub() Label_Duration.Text =
                          Duration_of_the_runtime.Days.ToString(Deu).PadLeft(3, "0"c) & ":" &
                          Duration_of_the_runtime.Hours.ToString(Deu).PadLeft(2, "0"c) & ":" &
                          Duration_of_the_runtime.Minutes.ToString(Deu).PadLeft(2, "0"c))

【问题讨论】:

  • 第二个问题的答案可以在docs.microsoft.com/en-us/dotnet/api/…找到TimeSpan.ToString("...")
  • @Mary 谢谢! Duration_of_the_runtime.ToString("ddd\:hh\:mm")
  • 美国价值观的旁注。只需使用整数(Int32)。见stackoverflow.com/questions/530690/net-optimized-int32
  • 我假设当你说“Cells 正在返回一个Range”时,你是通过文档还是某种运行时检查?因为错误提示即使返回值的运行时类型Range静态类型也是ObjectOption Strict On 不允许隐式转换,包括来自Object 的转换,因此您必须使用CTypeDirectCast。 (后者将避免在运行时类型不匹配时尝试查找转换的一些小开销。)
  • 因此您可以确信将结果转换为Range 会起作用。这种不幸的设计可能与 Excel 自动化对象模型有关,在我的记忆中,由于有很多遗留包袱,使用它并不是最友好的。如果您发现 PITA 的投射量过多,您可以随时转Option Strict Off,我通常不会推荐,但也有例外。 (我想我是在我自己的一些 Excel 自动化代码上这样做的,因为界面的类型很松散。)

标签: excel vb.net


【解决方案1】:

对于您的主要问题,不,您没有做错任何事情,这就是 Excel 自动化界面的行为方式。具体来说,集合类型都是经典的 VBA Collection(或等效的功能),这意味着索引访问返回 Object 而不是强类型。

正如您所指出的,如果您尝试在 Option Strict On 上下文中使用它,您将不得不转换结果。我自己的具有大量集合项访问权限的互操作代码中到处都是 DirectCast(.Rows(2), Excel.Range)...

【讨论】:

    猜你喜欢
    • 2012-05-12
    • 2011-09-03
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    • 2020-05-16
    • 1970-01-01
    相关资源
    最近更新 更多