水如烟

                 顺其自然,水到渠成 LzmTW

文或代码皆是面向初学者.我是爱好者,也是初学者.那些"文章",只按自己理解写,我是不知术语名词的.所以只供参考,也仅供参考.

导航

关于异常的简单思考

Posted on 2005-10-25 17:47  水如烟(LzmTW)  阅读(871)  评论(4编辑  收藏  举报
Author:水如烟

     一、异常是避免不了的
     异常是避免不了的。比如将一个八位数字字串转换为相应的日期。
     初始的代码如下:

Public Class Dig8ToDateTime

    
Private Const DIG8_PATTERN As String = "\b(\d{4})(\d{2})(\d{2})\b"
    
Private Const DIG8_REPLACEMENT As String = "${1}-${2}-${3}"

    
'将8位数字转换为日期表示格式,如"20051025"转换为"2005-10-25"
    Private Shared Function ToDateFormat(ByVal Value As StringAs String
        
Return System.Text.RegularExpressions.Regex.Replace(Value, DIG8_PATTERN, DIG8_REPLACEMENT)
    
End Function


    
Public Shared Function ToDateTime(ByVal Value As StringAs DateTime
        
Return DateTime.Parse(ToDateFormat(Value))
    
End Function


End Class
 
    当接受的字串真是符合日期转换时,当然一切正常。

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Console.WriteLine(Dig8ToDateTime.ToDateTime(
"20051031").ToLongDateString)
    
End Sub


    
'输出结果:2005年10月31日

     但是当字串不符合日期转换时,就发生异常了。

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Console.WriteLine(Dig8ToDateTime.ToDateTime(
"2005093").ToLongDateString)
    
End Sub


     在这个类,能够避免预知的错误吗?能够利用Try...Catch...Finnaly吗?无论我怎么努力,我发现,无法避免,也不能使用Try...Catch。我就算告诉用户,你的输入错了,但我也无法输出合理的结果。能Return Nothing吗?不能!Nothing在DataTime里头就是0001年1月1日。为此,我只能什么都不处理,就让它异常好了。

     二、异常真的不能避免吗
     老天,我象是自打嘴巴了。
     为了正常使用Dig8ToDateTime,我必须在用户界面上来检测输入是否合法。当我做到了这一步时,认为合法了,我发现,结果已经出来了,根本没有再使用Dig8ToDateTime这个类的必要。就是说,Dig8ToDateTime类毫无使用价值。
     可我喜欢这个类,它在合法输入时带给我方便。现在,我变通一下,在输出结果前强制自检,不经自检,就不能使用Dig8ToDateTime.ToDateTime。
     现在的代码如下:

Public Class Dig8ToDateTime

    
Private Const DIG8_PATTERN As String = "\b(\d{4})(\d{2})(\d{2})\b"
    
Private Const DIG8_REPLACEMENT As String = "${1}-${2}-${3}"

    
Private Shared IsOK As Boolean
    
Private Shared Result As DateTime

    
'将8位数字转换为日期表示格式,如"20051025"转换为"2005-10-25"
    Private Shared Function ToDateFormat(ByVal Value As StringAs String
        
Return System.Text.RegularExpressions.Regex.Replace(Value, DIG8_PATTERN, DIG8_REPLACEMENT)
    
End Function


    
Public Shared Function CheckInput(ByVal Value As StringAs Boolean
        
Try
            Result 
= DateTime.Parse(ToDateFormat(Value))
            IsOK 
= True
        
Catch ex As Exception
            IsOK 
= False
        
End Try
        
Return IsOK
    
End Function


    
Public Shared Function Value() As DateTime
        
If Not IsOK Then
            
Throw New ApplicationException("请使用如下方法" & System.Environment.NewLine & _
                        
"Dim t As DateTime" & System.Environment.NewLine & _
                        
"If Dig8ToDateTime.CheckInput(""20051201"") Then " & System.Environment.NewLine & _
                        
"   t = Dig8ToDateTime.Value" & System.Environment.NewLine & _
                        
"Else " & System.Environment.NewLine & _
                        
"   MsgBox(""输入错误"") " & System.Environment.NewLine & _
                        
"End If")
        
End If
        IsOK 
= False
        
Return Result
    
End Function


End Class

     用户(这里指编程者)在使用这个类,在不知其特殊用法的情况下,一般是这样写的:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dig8ToDateTime.CheckInput(
"20050930")
        Console.WriteLine(Dig8ToDateTime.Value.ToLongDateString)
    
End Sub
 
     在合法输入时,是正确的;不合法时,当然会发生异常:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dig8ToDateTime.CheckInput(
"2005093")
        Console.WriteLine(Dig8ToDateTime.Value.ToLongDateString)
    
End Sub



     于是会修改代码:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        
If Dig8ToDateTime.CheckInput("200509"Then
            Console.WriteLine(Dig8ToDateTime.Value.ToLongDateString)
        
Else
            
MsgBox("输入错误")
        
End If
    
End Sub

     三、尽早预防异常
     如果事前知道输入非法,那就可以即时回头,告知用户。下面,我加强了对数字合理性的判别。

Public Class Dig8ToDateTime
    
Private Const DIG8_PATTERN As String = "\b(0\d{2}[1-9]|[1-9]\d{3})(0[1-9]|1[0-2])(0[1-9]|[1|2]\d|3[0-1])\b"
    
Private Const DIG8_REPLACEMENT As String = "${1}-${2}-${3}"

    
Private Shared IsOK As Boolean
    
Private Shared Result As DateTime

    
'将8位数字转换为日期表示格式,如"20051025"转换为"2005-10-25"
    Private Shared Function ToDateFormat(ByVal Value As StringAs String
        
Return System.Text.RegularExpressions.Regex.Replace(Value, DIG8_PATTERN, DIG8_REPLACEMENT)
    
End Function


    
Public Shared Function CheckInput(ByVal Value As StringAs Boolean
        
Dim f As String = ToDateFormat(Value)
        
If Not f.Length = 10 Then 'Return False
            IsOK = False
            
Return IsOK
        
End If

        
Try
            Result 
= DateTime.Parse(f)
            IsOK 
= True
        
Catch ex As Exception
            IsOK 
= False
        
End Try
        
Return IsOK
    
End Function


    
Public Shared Function Value() As DateTime
        
If Not IsOK Then
            
Throw New ApplicationException("请使用如下方法" & System.Environment.NewLine & _
                        
"Dim t As DateTime" & System.Environment.NewLine & _
                        
"If Dig8ToDateTime.CheckInput(""20051201"") Then " & System.Environment.NewLine & _
                        
"   t = Dig8ToDateTime.Value" & System.Environment.NewLine & _
                        
"Else " & System.Environment.NewLine & _
                        
"   MsgBox(""输入错误"") " & System.Environment.NewLine & _
                        
"End If")
        
End If
        IsOK 
= False
        
Return Result
    
End Function


End Class


     四、尽可能减少异常抛出时间 
     Dig8ToDateTime类内还是不能避开异常的发生。闰年的二月,每月的31,不好判断。是能判断,可要做到的话,那这个类真没价值了。我只好用Try...Catch来应付。真遇到这种的非法输入时,肯定会发生异常,只不过是将异常控制在Try块内。这里还有没有改进的地方?既然避免不了异常的抛出,能不能缩短抛出的时间?以下想法只是估测,实际不知有没有用。
     当运行环境遇到异常时,NET会寻找异常的类型,在运行库的异常数组里找,找到匹配的了,才抛出这个异常。我想的是能不能缩短它寻找的时间。看了帮助文档,DateTime.Parse()抛出异常的类型是FormatException,我就用它来代替Exception。实际上有没有效果呢,我真不知道。

Public Class Dig8ToDateTime
    
Private Const DIG8_PATTERN As String = "\b(0\d{2}[1-9]|[1-9]\d{3})(0[1-9]|1[0-2])(0[1-9]|[1|2]\d|3[0-1])\b"
    
Private Const DIG8_REPLACEMENT As String = "${1}-${2}-${3}"

    
Private Shared IsOK As Boolean
    
Private Shared Result As DateTime

    
'将8位数字转换为日期表示格式,如"20051025"转换为"2005-10-25"
    Private Shared Function ToDateFormat(ByVal Value As StringAs String
        
Return System.Text.RegularExpressions.Regex.Replace(Value, DIG8_PATTERN, DIG8_REPLACEMENT)
    
End Function


    
Public Shared Function CheckInput(ByVal Value As StringAs Boolean
        
Dim f As String = ToDateFormat(Value)
        
If Not f.Length = 10 Then 'Return False
            IsOK = False
            
Return IsOK
        
End If

        
Try
            Result 
= DateTime.Parse(f)
            IsOK 
= True
        
Catch ex As FormatException
            IsOK 
= False
        
End Try
        
Return IsOK
    
End Function


    
Public Shared Function Value() As DateTime
        
If Not IsOK Then
            
Throw New ApplicationException("请使用如下方法" & System.Environment.NewLine & _
                        
"Dim t As DateTime" & System.Environment.NewLine & _
                        
"If Dig8ToDateTime.CheckInput(""20051201"") Then " & System.Environment.NewLine & _
                        
"   t = Dig8ToDateTime.Value" & System.Environment.NewLine & _
                        
"Else " & System.Environment.NewLine & _
                        
"   MsgBox(""输入错误"") " & System.Environment.NewLine & _
                        
"End If")
        
End If
        IsOK 
= False
        
Return Result
    
End Function


End Class

     这个类,我现在只能做成这样了。最后发现,无论如何,异常还是免不了的。并且,我还主动的生成新的异常New ApplicationException。
     最后是这样,将Value改成属性。
''' -----------------------------------------------------------------------------
'
'' Project     : LzmTW.Common
'
'' Class     : Common.Dig8ToDateTime
'
'' 
'
'' -----------------------------------------------------------------------------
'
'' <summary>
'
'' 将8位数字串转换为日期
'
'' </summary>
'
'' <remarks>
'
'' 请按 "IF CheckInput(Value) Then  Else EndIf" 方式使用
'
'' </remarks>
'
'' <history>
'
''     [lzmtw]    2005-10-26    Created
'
'' </history>
'
'' -----------------------------------------------------------------------------
Public Class Dig8ToDateTime
    
'日期型数字匹配正则表达式
    Private Const DIG8_PATTERN As String = "\b(0\d{2}[1-9]|[1-9]\d{3})(0[1-9]|1[0-2])(0[1-9]|[1|2]\d|3[0-1])\b"
    
Private Const DIG8_REPLACEMENT As String = "${1}-${2}-${3}"

    
Private Shared _IsOK As Boolean
    
Private Shared _Result As DateTime

    
Private Sub New()
    
End Sub


    
Private Shared Function ToDateFormat(ByVal Value As StringAs String '将20051210转换为2005-12-10
        Return System.Text.RegularExpressions.Regex.Replace(Value, DIG8_PATTERN, DIG8_REPLACEMENT)
    
End Function


    
''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 输入
    ''' </summary>
    ''' <param name="Value">8位数字串</param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    '''     [lzmtw]    2005-10-26    Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Shared Function CheckInput(ByVal Value As StringAs Boolean
        
Dim f As String = ToDateFormat(Value)
        
If Not f.Length = 10 Then
            _IsOK 
= False
            
Return _IsOK
        
End If

        
Try
            _Result 
= DateTime.Parse(f)
            _IsOK 
= True
        
Catch ex As FormatException
            _IsOK 
= False
        
End Try
        
Return _IsOK
    
End Function


    
''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 返回值
    ''' </summary>
    ''' <value></value>
    ''' <remarks>
    ''' 按 "IF CheckInput(Value) Then  Else EndIf" 方式使用
    ''' </remarks>
    ''' <history>
    '''     [lzmtw]    2005-10-26    Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Shared ReadOnly Property Value() As DateTime
        
Get
            
If Not _IsOK Then
                
Throw New ApplicationException("请使用如下方法" & System.Environment.NewLine & _
                            
"Dim t As DateTime" & System.Environment.NewLine & _
                            
"If Dig8ToDateTime.CheckInput(""20051201"") Then " & System.Environment.NewLine & _
                            
"   t = Dig8ToDateTime.Value" & System.Environment.NewLine & _
                            
"Else " & System.Environment.NewLine & _
                            
"   MsgBox(""输入错误"") " & System.Environment.NewLine & _
                            
"End If")
            
End If
            _IsOK 
= False
            
Return _Result
        
End Get
    
End Property


End Class


     测试代码:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        
Dim Dig8Converter As LzmTW.Common.Dig8ToDateTime
        
With Dig8Converter
            
If .CheckInput(Me.TextBox1.Text) Then
                
Me.TextBox2.Text = .Value.ToLongDateString
            
Else
                
Me.TextBox2.Text = "输入错误"
                
'如显示异常信息 Console.WriteLine(.Value)
            End If
        
End With

    
End Sub