2012-12-29 11 views
5

È possibile in vb.net avere un metodo che costruisca un oggetto di qualsiasi classe derivata nella classe di basso? In questo codice x.Clone dovrebbe restituire un oggetto Bar. È l'unico modo per dulpicare il codice in entrambe le classi con entrambi i tipi di oggetto.Costruire un oggetto di tipo derivato in Oggetto base

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 

risposta

3

La risposta dipende in particolare da cosa si sta tentando di ottenere nel metodo di clonazione.

Se si desidera creare una nuova istanza della classe corrente senza effettivamente copiare nessuna delle proprietà (che potrebbe sembrare interessante in base al codice di esempio e alla descrizione), la soluzione semplice è:

Public Class Foo 
    Implements ICloneable 

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

è possibile verificare che questo è chiamato con l'aggiunta di un messaggio (o una sorta di debug o di uscita) in bar:

Public Class Bar 
    Inherits Foo 

    Public Sub New() 
     MsgBox("Test") 
    End Sub 

End Class 

Se avete Option Strict On, che consiglio vivamente, il codice principale sarebbe:

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

Tuttavia, se siete interessati a copiare i valori dei membri della classe corrente, è possibile utilizzare MemberwiseClone:

Public Class Foo 
    Implements ICloneable 

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

Tuttavia, questo sarà solo creare una copia, sarà copiare i riferimenti, e non invocherà il costruttore su Bar. Quando usiamo MemberwiseClone in questo modo, aggiungiamo sempre un metodo override, che può essere utilizzato da eredi per eseguire post-clone di pulizia:

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 

Infine, se la copia superficiale o trattare con riferimenti copiati non è a voi che gradite, è possibile eseguire una copia completa utilizzando un trucco a buon mercato, ma molto efficace: la serializzazione e deserializzazione utilizzando il 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 

Ciò richiede che le classi siano serializzabili, ma che è facile da fare.

+0

+1 ma non mi piace questo stile di VB; anche se il compilatore non lo impone dovresti qualificare le tue chiamate di funzione con parentesi per distinguerle dagli accessi di proprietà: cioè scrivere 'Me.GetType()' invece di 'Me.GetType' ecc. –

+0

@KonradRudolph: Grazie per il +1. Sono d'accordo e seguo sempre questo nel codice di produzione, ma per aver semplicemente riunito un campione veloce, ho pensato che sarebbe andato tutto bene. –

Problemi correlati