【问题标题】:Constructing object of derived type in Base object在 Base 对象中构造派生类型的对象
【发布时间】:2012-12-29 23:01:50
【问题描述】:

在vb.net中是否有可能有一个方法来构造bass类中任何派生类的对象? 在这段代码中,x.Clone 应该返回一个 Bar 对象。 是使用两种不同对象类型复制两个类中的代码的唯一方法。

Module Module1

    Sub Main()
        Dim x As New Bar
        Dim y As Bar = x.Clone
    End Sub

End Module

Public Class Foo
    Implements ICloneable
    Public Function Clone() As Object Implements System.ICloneable.Clone
        Clone = Me.new() 'fails to compile as not in a constructor
        Clone = new Foo 'constructs a new foo in the derived class
    End Function
End Class

Public Class Bar
    Inherits Foo
    'additional implementation
    'but no addition fields
End Class

【问题讨论】:

    标签: .net vb.net class


    【解决方案1】:

    答案具体取决于您在克隆方法中尝试完成的任务。

    如果您想在不实际复制任何属性的情况下创建当前类的新实例(根据示例代码和描述,您可能有兴趣这样做),那么简单的解决方案是:

    Public Class Foo
        Implements ICloneable
    
        Public Function Clone() As Object Implements System.ICloneable.Clone
            Return Activator.CreateInstance(Me.GetType)
        End Function
    End Class
    

    您可以通过在 Bar 中添加消息(或某种调试或输出)来测试它是否被调用:

    Public Class Bar
        Inherits Foo
    
        Public Sub New()
            MsgBox("Test")
        End Sub
    
    End Class
    

    如果你有Option Strict On,我强烈推荐,main 中的代码是:

    Sub Main()
        Dim x As New Bar
        Dim y As Bar = DirectCast(x.Clone, Bar)
    End Sub
    

    但是,如果您有兴趣从当前类中复制成员值,可以使用MemberwiseClone:

    Public Class Foo
        Implements ICloneable
    
        Public Function Clone() As Object Implements System.ICloneable.Clone
            Return Me.MemberwiseClone
        End Function
    End Class
    

    但是,这只会创建一个浅拷贝,将复制引用,并且不会调用 Bar 上的构造函数。当我们以这种方式使用 MemberwiseClone 时,我们总是添加一个可被继承者用来执行克隆后清理的可覆盖方法:

    Public Class Foo
        Implements ICloneable
    
        Public Function Clone() As Object Implements System.ICloneable.Clone
            Dim oObject As Foo
    
            oObject = DirectCast(Me.MemberwiseClone, Foo)
            oObject.PostCloneCleanup()
    
            Return oObject
        End Function
    
        Protected Overridable Sub PostCloneCleanup()
    
        End Sub
    End Class
    
    Public Class Bar
        Inherits Foo
    
        Public Sub New()
            MsgBox("Test")
        End Sub
    
        Protected Overrides Sub PostCloneCleanup()
            MsgBox("PostCloneCleanup")
        End Sub
    
    End Class
    

    最后,如果你不喜欢浅拷贝或处理拷贝的引用,你可以使用一种廉价但非常有效的技巧来执行深拷贝:使用 BinaryFormmater 进行序列化和反序列化:

    Public Function CreateDeepCopy(Of T)(ByVal oRecord As T) As T
    
        If oRecord Is Nothing Then
            Return Nothing
        End If
    
        If Not oRecord.GetType.IsSerializable Then
            Throw New ArgumentException(oRecord.GetType.ToString & " is not serializable")
        End If
    
        Dim oFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
    
        Using oStream As IO.MemoryStream = New IO.MemoryStream
            oFormatter.Serialize(oStream, oRecord)
            oStream.Position = 0
            Return DirectCast(oFormatter.Deserialize(oStream), T)
        End Using
    End Function
    

    这要求类是可序列化的,但这很容易做到。

    【讨论】:

    • +1 但我不喜欢这种风格的 VB;即使编译器没有强制要求,你也应该用括号限定你的函数调用,以将它们与属性访问区分开来:也就是说,写 Me.GetType() 而不是 Me.GetType 等。
    • @KonradRudolph:感谢您的 +1。我同意并始终在生产代码中遵循这一点,但只是将一个快速示例放在一起,我认为它会很好。
    猜你喜欢
    • 1970-01-01
    • 2021-12-28
    • 2011-10-15
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-05
    相关资源
    最近更新 更多