如何在类中创建一个通用方法?

3

我真的在努力遵循DRY原则。我有一个子程序看起来像这样:

Private Sub DoSupplyModel

        OutputLine("ITEM SUMMARIES")
        Dim ItemSumms As New SupplyModel.ItemSummaries(_currentSupplyModel, _excelRows)
        ItemSumms.FillRows()
        OutputLine("")

        OutputLine("NUMBERED INVENTORIES")
        Dim numInvs As New SupplyModel.NumberedInventories(_currentSupplyModel, _excelRows)
        numInvs.FillRows()
        OutputLine("")   

End Sub

我希望使用泛型将它们合并为一个方法。值得注意的是,ItemSummaries和NumberedInventories都派生自同一基类DataBuilderBase。
我无法找出允许我在该方法中执行ItemSumms.FillRows和numInvs.FillRows的语法。
FillRows在基类中声明为Public Overridable Sub。
提前感谢您的帮助。
编辑: 这是我的最终结果。
Private Sub DoSupplyModels()

    DoSupplyModelType("ITEM SUMMARIES",New DataBlocks(_currentSupplyModel,_excelRows)
    DoSupplyModelType("DATA BLOCKS",New DataBlocks(_currentSupplyModel,_excelRows)

End Sub

Private Sub DoSupplyModelType(ByVal outputDescription As String, ByVal type As DataBuilderBase)
    OutputLine(outputDescription)
    type.FillRows()
    OutputLine("")
End Sub

但是回答自己的问题...我本可以这样做...

Private Sub DoSupplyModels()

    DoSupplyModelType(Of Projections)("ITEM SUMMARIES")
    DoSupplyModelType(Of DataBlocks)("DATA BLOCKS")

End Sub

Private Sub DoSupplyModelType(Of T as DataBuilderBase)(ByVal outputDescription As String, ByVal type As T)
    OutputLine(outputDescription)
    Dim type as New DataBuilderBase (_currentSupplyModel,_excelRows)
    type.FillRows()
    OutputLine("")
End Sub

这样对吗?

Seth


一个 C# 的例子会有帮助吗? - Roman
你想把DoSupplyModel更改为接收ItemSummariesNumberedInventories吗?如果是,那么你可以简单地使用基类DataBuilderBase作为参数类型进行接收。在这种情况下,你不需要使用泛型。 - Jorge Ferreira
C#没问题,如果我不懂的话我可以转换它,但是我很好地阅读C#。 - Seth Spearman
smink...你是对的...在我的例子中不需要泛型...但我仍然想知道如何做到这一点。 - Seth Spearman
4个回答

3

正如其他人指出的那样,您不需要泛型来实现您想要的功能,但我将为完整起见回答技术问题:

Private Sub MyMethod(Of T As DataBuilderBase)(ByVal instance As T)
    instance.FillRows()
End Sub

然后通过以下方式调用该方法:

MyMethod(Of ItemSummaries)(new SupplyModel.ItemSummaries(...))

感谢您用正确的语言实际回答了这个问题。 - Roman

1

你可以重构代码以利用它们共享的基类并使用多态性:(VB 有点生疏,但你应该能理解)

你可以创建一个方法:

Private Sub FillAndOutput(textToOutput as String, filler as DataBuilderBase)
    OutputLine(string)        
    filler.FillRows()
    OutputLine("")
end sub

你可以称之为:
Private Sub DoSupplyModel
    FillAndOutput("ITEM SUMMARIES",New SupplyModel.ItemSummaries(_currentSupplyModel, _excelRows))
    FillAndOutput("NUMBERED INVENTORIES",New SupplyModel.NumberedInventories(_currentSupplyModel, _excelRows))        

End Sub

我认为这已经是真的了,“FillRows”在基类中被声明为“Public Overridable Sub FillRows”。 - Roman

1
基本上,你需要指定 T 将是一个实现了 FillRows 方法的基类型的子类。在 C# 中,代码如下所示:
private void myFunction<T>( T someList ) where T : DataBuilderBase {
    someList.FillRows();
}

发现了一个在MSDN上的VB.NET 示例

编辑,Kevin是正确的,使用多态性可能会更好地处理这个问题。


这里的 T : DataBuilderBase 是我不理解如何实现的内容(换句话说,如何约束泛型类型)。在 VB 中,语法是 Private Sub myFunction(Of T As DataBuilderBase)(ByVal someList As T)。非常感谢。 - Seth Spearman

0
在这种情况下,我认为即使要重复自己,也不能证明将重构为通用函数。你有两个选择:
  1. 重构您的代码,以便允许无参数的构造函数,并创建一个更高级别的继承层次结构中的函数,允许您指定当前传递给构造函数的参数。
  2. 使用显式反射来实例化通用类型并将这些参数传递给构造函数。

这两个选项中的任何一个都涉及大量工作,但几乎没有什么收获(您将三行代码转换为一行)。

然而,回答您的问题,VB.NET使用of关键字指定泛型类型参数。

Public Sub Foo(Of T)(argument as T)
   ...
End Sub

我很好奇,为什么你认为这不是合理的? Seth - Seth Spearman
@Seth:相比于从中获得的好处,使它通用的成本太高了。您需要使其成为通用类型的唯一原因是要实例化泛型类型(这意味着您必须经历我在答案中列出的麻烦)或返回泛型类型以便您可以拥有更流畅的接口(我真的不认为这是情况)。除此之外,可以重构的部分仅是对“FillRows”的调用,我只是没有看到创建一个只调用另一个函数而没有逻辑的新函数的好处。 - Adam Robinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接