将结构作为ByValue传递给过程,但过程会更改原始结构值

时间:2014-02-06 07:21:26

标签: vb.net structure byval

我想问一下VB.NET代码。我经常遇到这个问题。如果您知道我的问题的解决方案或给我一些评论,请回答我。


'Declare a structure "Gene"
    Public Structure Gene
    Dim Seq() As Integer
    End Structure

'Here is a procedure, it changes original value.
        Public Sub Mutation(ByVal OriginalGene As Gene, ByRef TargetGene As Gene)
        Dim P1 As Integer
        Dim P2 As Integer
        Dim Temp As Integer

        P1 = Int((N_Jobs - 1 + 1) * Rnd(RndNum) + 0)
        P2 = Int((N_Jobs - 1 + 1) * Rnd(RndNum + 1) + 0)

        TargetGene.Seq = OriginalGene.Seq

        Temp = TargetGene.Seq(P1)
        TargetGene.Seq(P1) = TargetGene.Seq(P2)
        TargetGene.Seq(P2) = Temp
        End Sub

3 个答案:

答案 0 :(得分:1)

实际上并没有改变结构。所有结构都包含一个指向数组的指针。即使您可以拥有无​​限数量的结构副本,对数组的引用也始终相同。


不可变基因类的例子:

Public Class Gene
    Private _sequence() As Integer
    Public Sub New(sequence() As Integer)
        _sequence = sequence
    End Sub
    Public Function GetSequence() As Integer()
        Return _sequence.Select(Function (x) x).ToArray()
    End Function
    Public Function Mutate() As Gene
        Dim sequence() As Integer = Me.GetSequence()

        Dim P1 As Integer
        Dim P2 As Integer
        Dim Temp As Integer

        P1 = Int((N_Jobs - 1 + 1) * Rnd(RndNum) + 0)
        P2 = Int((N_Jobs - 1 + 1) * Rnd(RndNum + 1) + 0)

        TargetGene.Seq = OriginalGene.Seq

        Temp = sequence(P1)
        sequence(P1) = sequence(P2)
        sequence(P2) = Temp

        Return New Gene(sequence)
    End Function
End Class

答案 1 :(得分:0)

您需要实现结构的副本,尝试类似:

    Structure Gene
    Dim Seq() As Integer
    Public Function Clone() As Gene
        Dim mySt As Gene
        Array.Copy(Me.Seq, mySt.Seq, Me.Seq.Length)
        Return mySt
    End Function
End Structure

然后而不是:

TargetGene.Seq = OriginalGene.Seq

使用

TargetGene.Seq = OriginalGene.Clone()

答案 2 :(得分:0)

如果序列的长度是固定的,你可以使用fixed数组声明来保存它,但是固定数组需要“不安全”的代码,这在某些情况下可能会有问题。

否则,结构实际上没有很好的方法来封装具有值语义的非固定集合。如果希望结构传达用可变值语义封装集合的错觉,则必须使结构保持对数组或其他数据类型的私有引用,一旦引用存储到struct字段中,该数据类型将永远不会改变。如果要求结构更改包含的数据,则必须创建一个封装已更改数据的新对象。请注意,必须在存储引用之前进行任何更改。

使结构提供可变值语义的另一个困难是,没有任何方法可以通过该方法在结构上的实例方法可以指示它们是否可以安全地用于只读结构实例。实际上,在只读结构实例上不能使用任何结构方法或属性,但如果C#看到,例如

 someObject.propertyOfStructType.doSomething();

它会默默地将代码重写为

 var temp = someObject.propertyOfStructType;
 temp.doSomething();

有时替代是安全的。有时它不是。虽然编译器检查方法是否标记为“不在只读结构上使用”属性并且拒绝对这些方法使用上述替换应该很简单,但是没有记录用于此目的的属性。因此,如果想要提供一种安全的方法,例如,将一系列值从一个数组复制到一个值数组类型,必须编写并调用该方法,如下所示:

public static int LoadFromEnumerable(ref ValueArray<T> it, int startIndex, IEnumerable<T> source);

int numElementsAdded = ValueArray<int>.LoadFromEnumerable(ref myValueArray, 4, myIntegers);

而不是看起来更干净的

public int LoadFromEnumerable(int startIndex, IEnumerable<T> source);

myValueArray.LoadFromEnumerable(4, myIntegers);
相关问题