我想出了一个看起来不错的模式。它的灵感来自某个人在 CodeProject.com 上发布的内容——使用列表来跟踪一次性用品; raiiBase(of T) 是一个基类,适用于其构造函数采用单个参数的任何类。必须保护类构造函数,并且必须通过工厂方法进行构造。静态 makeRaii() 构造函数接受一个工厂函数的委托,该函数必须接受一个 Stack(of iDisposable) 以及该类预期类型的参数。示例用法:
公开课 RaiiTest
继承 raiiBase(Of String)
Dim thing1 As testDisposable = RAII(New testDisposable("Moe" & creationParam, "a"))
Dim thing2 As testDisposable = RAII(New testDisposable("Larry " & creationParam, "b"))
Dim thing3 As testDisposable = RAII(New testDisposable("Shemp" & creationParam, "c"))
Dim thing4 As testDisposable = RAII(New testDisposable("Curly" & creationParam, "d"))
Protected Sub New(ByVal dispList As Stack(Of IDisposable), ByVal newName As String)
MyBase.New(dispList, newName)
结束子
私有共享函数 _newRaiiTest(ByVal dispList As Stack(Of IDisposable), ByVal theName As String) As RaiiTest
返回新的 RaiiTest(dispList, theName)
结束功能
公共共享函数 newRaiiTest(ByVal theName As String) As RaiiTest
返回 makeRaii(Of RaiiTest)(AddressOf _newRaiiTest, theName)
结束功能
共享子测试(ByVal st As String)
尝试
使用它作为 RaiiTest = newRaiiTest(st)
Debug.Print("现在使用对象")
结束使用
Debug.Print("没有抛出异常")
捕获 ex As raiiException
Debug.Print("输出异常:" & ex.Message)
If ex.InnerException IsNot Nothing Then Debug.Print("Inner exception: " & ex.InnerException.Message)
对于每个 exx 作为 ex.DisposalExceptions 中的异常
Debug.Print("处理异常:" & exx.Message)
下一个
抓住前任作为例外
Debug.Print("杂项异常:" & ex.Message)
结束尝试
结束子
结束类
由于 raiiTest 继承 raiiBase(of String),要创建类实例,请使用字符串参数调用 newRaiiTest。 RAII() 是一个通用函数,它将其参数注册为需要清理的 iDisposable,然后返回它。当在主对象上调用 Dispose 或在主对象的构造中引发异常时,所有已注册的可处置对象都将被 Disposed。
这是 riaaBase 类:
选项严格开启
类 raiiException
继承异常
只读 _DisposalExceptions() 作为异常
Sub New(ByVal message As String, ByVal InnerException As Exception, ByVal allInnerExceptions As Exception())
MyBase.New(消息,InnerException)
_DisposalExceptions = allInnerExceptions
结束子
公共可重写只读属性 DisposalExceptions() As Exception()
得到
返回 _DisposalExceptions
结束获取
结束属性
结束类
公共类 raiiBase(Of T)
实现 IDisposable
受保护的 raiiList 作为堆栈(IDisposable 的)
受保护的创作Param As T
委托函数 raiiFactory(Of TT As raiiBase(Of T))(ByVal theList As Stack(Of IDisposable), ByVal theParam As T) As TT
共享函数 CopyFirstParamToSecondAndReturnFalse(Of TT)(ByVal P1 As TT, ByRef P2 As TT) As Boolean
P2 = P1
返回假
结束功能
共享函数 makeRaii(Of TT As raiiBase(Of T))(ByVal theFactory As raiiFactory(Of TT), ByVal theParam As T) As TT
将 dispList 调暗为新堆栈(IDisposable 的)
Dim constructionFailureException As Exception = Nothing
尝试
返回 theFactory(dispList, theParam)
当 CopyFirstParamToSecondAndReturnFalse 时将 ex 作为异常捕获(例如,constructionFailureException)
' 上面的语句让我们无需捕获并重新抛出即可找出发生了什么异常
Throw ' 不应该发生,因为我们应该在上面返回 false
最后
If constructionFailureException IsNot Nothing Then
zapList(dispList, constructionFailureException)
万一
结束尝试
结束功能
Protected Sub New(ByVal DispList As Stack(Of IDisposable), ByVal Params As T)
Me.raiiList = DispList
Me.creationParam = 参数
结束子
公共共享子 zapList(ByVal dispList As IEnumerable(Of IDisposable),ByVal triggerEx As Exception)
使用枚举作为 IEnumerator(Of IDisposable) = dispList.GetEnumerator
尝试
而 Enum.MoveNext
theEnum.Current.Dispose()
结束时
抓住前任作为例外
将 exList 调暗为新列表(例外)
exList.Add(ex)
而 Enum.MoveNext
尝试
theEnum.Current.Dispose()
将 ex2 捕获为异常
exList.Add(ex2)
结束尝试
结束时
Throw New raiiException("RAII 失败", triggerEx, exList.ToArray)
结束尝试
结束使用
结束子
函数 RAII(Of U As IDisposable)(ByVal Thing As U) As U
raiiList.Push(事物)
退货
结束功能
Shared Sub zap(ByVal Thing As IDisposable)
If Thing IsNot Nothing Then Thing.Dispose()
结束子
Private raiiBaseDisposeFlag As Integer = 0 ' 检测冗余调用
' 一次性
受保护的可覆盖子处置(ByVal 处置为布尔值)
如果处理 AndAlso Threading.Interlocked.Exchange(raiiBaseDisposeFlag, 1) = 0 那么
zapList(raiiList,无)
万一
结束子
#Region " IDisposable 支持 "
' 此代码由 Visual Basic 添加以正确实现一次性模式。
Public Sub Dispose() 实现 IDisposable.Dispose
' 不要更改此代码。将清理代码放在上面的 Dispose(ByVal disposing As Boolean) 中。
处置(真)
GC.SuppressFinalize(Me)
结束子
#结束区域
结束类
请注意,如果任何或所有已注册的一次性对象的处置失败,将引发自定义异常类型。 InnerException 将指示构造函数是否失败;要查看哪些处理程序失败,请检查 DisposalExceptions。