4

在我的项目中,我经常利用表和底层的 ListObjects 和 ListColumns。我喜欢它们,因为它们比裸 Range 对象更容易引用和更新。然而,我仍然没有找到一种健全且可维护的方法来处理由许多 ListColumns 组成的多个 ListObjects,并在项目中的所有 Worksheets 中被引用。

假设我有一个工作表(将(名称)属性设置为“WorksheetA”),其中包含带有少量列(称为 Column1、Column2、...、Column10)的表(称为 TableA)。

现在我想从另一个工作表的代码中引用其中一列。我可以这样做:

WorksheetA.ListObjects("TableA").ListColumns("Column7")

现在,直接使用字符串是一种不好的做法,因为它很难维护并且容易出错。

所以现在怎么办?

我可以创建专用模块来将我的字符串存储为常量。例如,名为“常量”的模块:

Public Const TABLE_A As String = "TableA"
Public Const COLUMN7 As String = "Column7"

然后我的参考可以转换为:

WorksheetA.ListObjects(Constants.TABLE_A).ListColumns(Constants.COLUMN7)

但是,这种解决方案有一些缺点:

  1. 常量模块会随着每个表和列的添加而增长得快得离谱。
  2. 引用本身会增长并变得不那么可读。
  3. 所有工作簿中与表格相关的所有常量都被扔进一个巨大的坑中。

我可以在 WorksheetA 中存储常量,并通过以下公共函数使它们可用:

Private Const TABLE_A As String = "TableA"
Private Const COLUMN7 As String = "Column7"

Public Function GetTableAName() As String
    GetTableAName = TABLE_A
End Function

Public Function GetTableA() As ListObject
    Set GetTableA = WorksheetA.ListObjects(TABLE_A)
End Function

Public Function GetTableAColumn7() As ListColumn
    Set GetTableAColumn7 = GetTableA().ListColumns(COLUMN7)
End Function

这个解决方案实际上解决了上面提到的所有三个问题,但它仍然有点“脏”和耗时,因为添加新表需要为每列创建一个函数。

你有更好的想法如何处理这个问题吗?

EDIT1(为清楚起见):假设用户不得更改任何名称(表名或列名)。如果用户这样做,那是他/她的责任。

EDIT2(为清楚起见):我仅将 Column7 用作列名作为示例。让我们假设列具有更有意义的名称。

4

1 回答 1

1

这是我的两分钱。我不是一个受过教育的程序员,但我确实得到了报酬,所以我想这让我很专业。

第一道防线是我创建了一个类来为表格建模。我从表中填写类,甚至没有其他代码知道数据所在的位置。当我初始化时,我会运行类似的代码

clsEmployees.FillFromListObject wshEmployees.ListObjects(1)

然后在课堂上,代码看起来像

vaData = lo.DataBodyRange.Value
...
clsEmployee.EeName = vaData(i,1)
clsEmployee.Ssn = vaData(i,2) 
etc

每个工作表只有一个 ListObject。这是我的规则,我从不打破它。任何有权访问工作表的人都可以重新排列列并破坏我的代码。如果我想使用 Excel 作为数据库,有时我会这样做,那么这就是我承担的风险。如果它非常重要以至于我不能冒这个风险,那么我会将我的数据存储在 SQL Server、SQLite 或 JET 中。

我实际上可以调用 ListColumns 名称,而不是将范围放入数组中。这样,如果有人重新排列了列,我的代码仍然可以工作。但它介绍了他们可以重命名列,所以我只是用一种风险换另一种风险。它会使代码更具可读性,所以它可能是你想做的交易。我喜欢从数组中填充的速度,所以这就是我所做的交易。

如果我的项目足够小或者应该直接使用 ListObjects,那么我遵循与任何字符串相同的规则。

  • 我在代码中只使用一次字符串。
  • 如果我多次使用它,我会创建一个过程级常量
  • 如果我在多个过程中使用它,我会尝试将它作为参数传递
  • 如果我不能将它作为参数传递,我会创建一个模块级常量
  • 如果这两个程序在不同的模块中,我首先问自己为什么两个程序在使用相同常量的不同模块中。相关程序不应该在同一个模块中吗?
  • 如果这两个过程确实属于不同的模块,那么我尝试将它作为参数传递
  • 如果这些都不起作用,那么它确实是一个全局常量,我在我的 MGlobals 模块中进行了设置。

如果 MGlobals 占据了超过半个屏幕,我就做错了,我需要退后一步思考我想要完成的工作。然后我制作了一个自定义类。

于 2015-10-09T18:23:11.037 回答