【问题标题】:Assignment Operator "=" in VB.NETVB.NET 中的赋值运算符“=”
【发布时间】:2014-08-04 07:38:49
【问题描述】:

首先,我在这里知道类似的问题:Assignment "=" operator in VB.NET 1.1

假设我有一个包含 ArrayList 的 VB.NET 结构

 Structure MarbleCollection
    Private marbles As ArrayList
 End Structure

 Class Marble
    Public name As String
    Public radius As Double
 End Class

我想了解当我创建两个 MarbleCollection 实例并使用“=”运算符将一个分配给另一个时会发生什么:

 marbleCol1 = marbleCol2

根据上面链接的问题的公认答案:

如果类型是引用类型(即:类),则它是引用副本。如果是值类型(Structure),会逐个成员复制。

当执行逐个成员的“复制”时(分配值类型时),VB.NET 真的只是递归地调用每个成员的赋值运算符吗?如果是这样,那么在这里将一个 MarbleCollection 分配给另一个不会产生深拷贝,因为两个 marbles ArrayLists 之间的赋值运算符会产生一个引用副本.我想要一个深拷贝。

有没有一种方法可以让引用类型对象像值类型对象一样隐式复制自己?例如,我会发现扩展 ArrayList 类的功能很有用,但我不希望我的子类通过引用复制其 ArrayList 值,而是复制值.

举个具体的例子:

 Class BookList
    Inherits ArrayList
 End Class

我可以对 BookList 类做些什么(即实现一个接口),这样可以做到:

 books1 = books2

是否会复制 books2 中的值并将复制引用分配给 books1

我不希望在这里被灌输解决方案并继续前进;我希望能解释一下“=”运算符的实际功能并在内部决定它将如何执行分配(以及我如何影响它)。欢迎推广到其他语言。

编辑:

似乎有些混乱。我意识到重载“=”运算符是不可能的/不建议的。我想了解操作员是如何工作的。然后,我可以自己确定如何/是否可以通过键入赋值语句来执行深层复制。

例如,这可能是也可能不是正确的、完全描述性对操作员行为的定义:

  1. class1 = class2 - 将 class2 的引用复制到 class1。它们是同一个实例。
  2. struct1 = struct2 - 为 struct2 中的每个 member 执行 struct1.member = struct2.member
  3. primitive1 = primitive2 - 创建一个新的基元,复制 primitive2 的值并将相同的值写入新的基元,并给 primitive1 引用这个新创建的原语。

我正在寻找上述行为的明确大纲。

【问题讨论】:

  • 您是否研究过深度复制对象?
  • 我对此一无所知。如果我正确理解了含义,我确实想执行深层复制,是的。我不知道怎么做。
  • 您应该在结构上实现DeepCopy 方法来进行复制。您不应该尝试执行任何运算符重载,因为这通常会导致与 c# 不一致的行为,并且会使调试和维护变得比需要的更难。
  • 肯定有一些规范的方法可以改变赋值运算符的行为吗?关键是我希望我的班级的行为是直观的。我希望 books1 = books2 执行逐值复制。有没有办法做到这一点?
  • 也许这将是一个有用的阅读codeproject.com/Articles/36067/Shallow-and-Deep-Object-Copying。从您的问题的外观来看,您似乎非常了解,因为您提供了一个非常详细的问题。您可以实现 ICloneable,可以在此处找到这样做的示例java2s.com/Tutorial/VB/0160__Collections/DeepClone.htm

标签: .net vb.net assignment-operator


【解决方案1】:

首先 - 您不能覆盖赋值运算符 = (Why aren't assignment operators overloadable in VB.NET?)。 如果将结构分配给新结构,则仅复制值字段,引用字段将保持不变(因此您的新 MarbleCollection.marbles 将指向与原始 MarbleCollection.marbles 相同的对象)。您可以做的是实现自己的方法并调用该方法而不是进行深度克隆。

Structure MarbleCollection
    Private marbles As ArrayList
    Public Function Clone() As MarbleCollection
        Dim result = New MarbleCollection()
        If marbles IsNot Nothing Then
            For Each m As Marble In marbles
                result.marbles.Add(m.Clone())
            Next
        End If
        Return result
    End Function
End Structure

Class Marble
    Public name As String
    Public radius As Double
    Public Function Clone() As Marble
        Return DirectCast(Me.MemberwiseClone(), Marble)
    End Function
End Class

如果您正在寻找深度克隆的自动化,我通常会执行二进制序列化,然后是反序列化(这为您提供深度克隆);还有一些图书馆。

兴趣点 - ICloneable 界面。

编辑:

对于通过序列化自动克隆,您可以这样编写您的类:

(无耻地抄自Deep cloning objects

Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

''' <summary>
''' Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
''' Provides a method for performing a deep copy of an object.
''' Binary Serialization is used to perform the copy.
''' </summary>
Public NotInheritable Class ObjectCopier
    Private Sub New()
    End Sub
    ''' <summary>
    ''' Perform a deep Copy of the object.
    ''' </summary>
    ''' <typeparam name="T">The type of object being copied.</typeparam>
    ''' <param name="source">The object instance to copy.</param>
    ''' <returns>The copied object.</returns>
    Public Shared Function Clone(Of T)(source As T) As T
        If Not GetType(T).IsSerializable Then
            Throw New ArgumentException("The type must be serializable.", "source")
        End If

        ' Don't serialize a null object, simply return the default for that object
        If [Object].ReferenceEquals(source, Nothing) Then
            Return Nothing
        End If

        Dim formatter As IFormatter = New BinaryFormatter()
        Dim stream As Stream = New MemoryStream()
        Using stream
            formatter.Serialize(stream, source)
            stream.Seek(0, SeekOrigin.Begin)
            Return DirectCast(formatter.Deserialize(stream), T)
        End Using
    End Function
End Class

缺点:MemberwiseClone() 和所有“可深度克隆”对象都必须用&lt;Serializable()&gt; 属性标记会慢一些。

【讨论】:

  • 赋值运算符是否在内部使用 IClonable 对象的 .Clone() 方法?如果没有,我根本看不到使用 IClonable 的目的。您介意详细说明序列化路线及其提供的自动化吗?
  • @Myridium 不,它没有。而不是a = b,您只需写a = b.Clone()。您不能覆盖赋值运算符(即使可以,也不应该)。
  • @Ondrej Svejdar 看起来序列化路由只是实现显式 Clone() 方法的另一种方式。
  • @Myridium - 是的,但您不必自己编写显式 Clone() 的实现 - 只要对象是可序列化的。
  • 这个答案基本上是正确的,但我建议编写和使用复制构造函数而不是 Clone 方法。 Clone 只有在你想要多态复制时才有意义(通过ICloneable 接口),这对于值类型来说通常不是问题。
猜你喜欢
  • 1970-01-01
  • 2011-08-02
  • 2019-10-06
  • 2011-11-16
  • 2013-11-30
  • 2015-10-02
  • 1970-01-01
  • 2014-04-17
  • 2021-01-24
相关资源
最近更新 更多