【问题标题】:Constructor-chaining and null reference tests构造函数链接和空引用测试
【发布时间】:2011-09-07 21:23:19
【问题描述】:

如何在调用其他构造函数之前测试空值?

说:

  ' class MyHoyr '
  Public Sub New(ByVal myHour As MyHour)
    ' Can't doing it here !!!! '
    If myHour Is Nothing Then Throw New ArgumentNullException("myHour")

    ' Constructor call should be first '
    Me.New(myHour._timeSpan)

    ' Here is too late... '
  End Sub


  Private Sub New(ByVal timeSpan As TimeSpan)
    '.... '
  End Sub

【问题讨论】:

  • 在那种情况下你可能不能。
  • 为什么你不能在第一个构造函数中做到这一点?这是进行此类检查的自然场所。
  • 他在构造函数链接时取消引用myHour
  • 我投票将我的第一条评论修改为:在那种情况下,您可能无法以一种不错的方式

标签: .net vb.net oop exception-handling constructor


【解决方案1】:

我在 C# 中这样做的方式是在管道中使用静态方法,例如:

public MyHour(MyHour myHour) : this(GetTimeSpan(myHour))
{}

private static TimeSpan GetTimeSpan(MyHour myHour)
{
    if(myHour== null) throw new ArgumentNullException("myHour");
    return myHour._timeSpan;
}

private MyHour(TimeSpan timeSpan)
{...}

假设你可以在 VB 中做一些非常相似的事情。 (共享方法?)

Reflector 向我保证这会转化为:

Public Sub New(ByVal myHour As MyHour)
    Me.New(MyHour.GetTimeSpan(myHour))
End Sub

Private Sub New(ByVal timeSpan As TimeSpan)
End Sub

Private Shared Function GetTimeSpan(ByVal myHour As MyHour) As TimeSpan
    If (myHourIs Nothing) Then
        Throw New ArgumentNullException("myHour")
    End If
    Return myHour._timeSpan
End Function

【讨论】:

  • 很遗憾异常位置不会在构造函数中...不过也许这是一个解决方案
【解决方案2】:

一个丑陋的解决方法是扩展方法:

<Extension(), DebuggerNonUserCode()> _
Public Function EnsureNotNull(Of T As Class)(ByVal Value As T, _
                                             ByVal Arg As String) As T
    If Value Is Nothing Then Throw New ArgumentNullException(Arg)
    Return Value
End Function

像这样使用:

' class MyHour '
Public Sub New(ByVal myHour As MyHour)
    Me.New(myHour.EnsureNotNull("myHour")._timeSpan)

End Sub

【讨论】:

  • 为什么“丑”?看起来非常多才多艺。如果以这种流畅的风格使用,我可能会称之为EnsureNotNull,但无论如何。
  • 异常位置不会是构造函数,这就是为什么丑...)
  • 我不喜欢构造函数中任何“复杂”的东西(链式构造函数调用中的扩展方法会在代码审查期间引起我的兴趣)。我也同意你的命名建议,感觉它会返回一个值(而ThrowIfNull 似乎是void)。
  • @serhio:我已将DebuggerNonUserCode 属性添加到扩展程序以改善调试时的体验。
  • @sixlettervariables:你真的会在你的代码中使用这样的代码吗?
【解决方案3】:

处理这个问题的一个简单方法是使用“命名构造函数”的概念,也就是工厂方法。

Public Shared Function Create (ByValue myHour As MyHour) As Foo
  If myHour Is Nothing Then Throw New ArgumentNullException("myHour")
  Return New Foo(myHour._timeSpan)
End Function

Private Sub New(ByVal timeSpan As TimeSpan)
  '.... '
End Sub

您可以看到与 System.Drawing.Color.FromArgb 类似的示例,它们使用工厂方法来避免歧义。

【讨论】:

    【解决方案4】:

    我最初的冲动是建议您甚至没有采用 MyHour 实例的构造函数。相反,让用户检查类之外的任何内容:

    Public Function GetSomeClassInstance(ByVal mh As MyHour) As SomeClass
    
        If mh IsNot Nothing Then
            Return New SomeClass(mh.TimeSpan)
        Else
            Throw New ArgumentNullException("mh", "MyHour instance must not be Nothing)
        End If
    
    End Function
    

    但是,像这样使用私有构造函数来实际构造对象可能会起作用(未经测试):

    Public Class SomeClass
        Public Sub New(ByVal mh As MyHour)
            MyClass.New(Nothing, mh)
        End Sub
    
        Public Sub New(ByVal ts As TimeSpan)
            MyClass.New(ts, Nothing)
        End Sub
    
        Private Sub New(ByVal ts As TimeSpan?, ByVal mh As MyHour)
            Dim _timeSpanToUse As TimeSpan
    
            If ts IsNot Nothing Then
                _timeSpanToUse = ts.Value
            Else
                If mh IsNot Nothing Then
                    _timeSpanToUse = mh.TimeSpan
                Else
                    Throw New ArgumentNullException("mh", "The MyHour parameter was NULL")
                End If
            End If
    
            'Continue using _timeSpanToUse here...
        End Sub
    End Class
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-29
      • 1970-01-01
      • 2016-12-03
      • 2013-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多