通过向VB.NET函数添加可选参数来破坏现有代码的可能性?

时间:2017-11-02 14:41:03

标签: com overloading clr signature optional-parameters

如果我向一个在任何地方使用的函数添加一个新的可选参数,那么大型项目中的现有代码是否有可能爆炸?我知道我可以重载函数并将风险降至最低,但实际上......如果我坚持使用可选参数会有什么风险?

以下是一个例子:

    Public Function GetContent(ByVal URL As String, ByVal ID As String, Optional ByRef PageTitle As String = "") As String
        Try
            Dim web As New HtmlWeb()
            Dim doc As HtmlDocument = web.Load(URL)
            ID = "//div[@id='" & ID & "']"
            Dim ContentNode As HtmlNode = doc.DocumentNode.SelectSingleNode(ID)

            ' The two lines below are the mere extent of what's new inside this function, besides the new Optional ByRef parameter in its signature
            Dim PageTitleNode As HtmlNode = doc.DocumentNode.SelectSingleNode("//title")
            If Not PageTitleNode Is Nothing Then PageTitle = PageTitleNode.InnerHtml

            Return ContentNode.InnerHtml

        Catch ex As Exception
            Return "<h4> Bad. Very bad. </h4>"
        End Try
    End Function

PS:我想在事后评论我的问题,在下面阅读了其他人的回复并自己做了一些额外的研究。最初,我不想质疑使用可选参数的方法的有效性。这是VB.NET允许我做的事情,我觉得我有充分的权利使用 - 除此之外它非常方便!但是我的原始问题更多地涉及可选参数的实现方式是否存在差距,从编译到执行 - 我在设计代码时应该考虑的差距。我没有意识到与过载方法相关的可选参数方法的历史意义。我现在已经了解到,可选参数方法不存在差距或缺陷;相反,它是一个针对不同和较旧的关注点设计的解决方案,这些关注点被公共语言运行时的出现简单地覆盖了。我正在使用VS2013。当然,使用可选参数方法编译好的一切似乎运行良好但我想通过添加一个可选参数来确认我不可能破坏别的东西 - 特别是因为有人看了我的代码并建议我应该重载函数而不是。我想证明为什么我不应该保留我的可选参数方法。我想,詹姆斯索普现在为我回答了这个问题。但正如Tim Schmelter所问,与过载方法相比,这样做是否有好处(可选参数)?对我来说,现在过载方法似乎是最好也是唯一的方法,那是因为我使用了一套更新的技术,可选参数方法 - 这是为Microsoft的旧组件对象模型或COM实现的 - 简直就是'旨在解决的问题(参见本书第83页,"Microsoft Visual C# 2013 Step By Step" by John Sharp)。特别是现在,如果有外部模块希望找到旧的函数签名(即我添加新的可选参数之前存在的函数参数布局),除非我重新编译它们,否则它们会破坏!这对我来说是一个障碍。但是重载更好地处理了这个软件开发问题,而不需要重新编译,现在只有新的Common Languange Runtime或CLR才支持。我认为VB.NET中的可选参数支持现在是旧COM时代的历史保留 - 而不是针对我的特定需求的最佳解决方案。我还刚刚了解到,“公共语言规范定义了所有语言应该支持的CLR子集,明确禁止依赖可选参数。这意味着它们不适合在基类库和可能永远不会出现在作为.NET Framework一部分提供的任何其他库中。“ (来自在线文章,"Optional Parameters Are Gaining Ground in .NET", by Jonathan Allen)。尽管对于使用Microsoft技术的常规开发人员而言规则较为宽松,但我认为他们内部决定不依赖可选参数可以说些什么。我只想发布并与你分享,如果像我一样,你也来这里想知道!

2 个答案:

答案 0 :(得分:4)

在一个项目中?不,应该没问题。但是,你在评论中说:

  

让我们说有其他项目称之为(有可能)。如果我没有重建它们会破坏那些吗?

可选参数实际上是在编译时烘焙的,因此如果您有原始方法签名:

Public Function GetContent(ByVal URL As String, ByVal ID As String)

有人正在这样称呼它:

GetContent(someUrl, someId)

它将按原样编译到程序集中。使用新的可选参数,在不传递参数的情况下调用它的任何内容实际上都会编译为:

GetContent(someUrl, someId, "")

注意如何自动引入可选参数的默认值。如果您正在重建所有内容,那一切都很好。但是,在那些引用未重建的项目中,它们将具有原始的双参数调用。您的GetContent方法现在在运行时需要3个参数 - 您将收到运行时错误,因为它无法找到仍然需要2个参数的函数的重载。

答案 1 :(得分:2)

以下是如何在不破坏代码的情况下完成的工作......

Public Function GetContent(ByVal URL As String, ByVal ID As String, ByRef PageTitle As String = "") As String
    ' the rest of your function here
End Function

Public Function GetContent(ByVal URL As String, ByVal ID As String) As String
    Return GetContent(URL, ID, "")
End Function

这样你就拥有了一个版本的函数,其中包含现有代码的2个参数和一个3个参数。

如果您想鼓励程序员切换到3参数版本,那么您可以像这样标记2参数版本:

<Obsolete("Use the version that takes pageTitle as a 3rd parameter">
Public Function GetContent(ByVal URL As String, ByVal ID As String) As String
    Return GetContent(URL, ID, "")
End Function

如果您尝试调用2参数版本,那将为您提供编译器警告。