在属性Get上设置VB.NET 2012属性

在属性Get上设置VB.NET 2012属性,vb.net,properties,.net-2.0,visual-studio-2012,Vb.net,Properties,.net 2.0,Visual Studio 2012,我在VS 2012 RC VB.NET项目中遇到了一个非常奇怪的情况,目标是.NET 2.0。出于某种原因,除了调用属性的Get方法外,还会调用属性的Set方法: 这与预期的效果一样: Dim _searchparray = New Byte() {37, 115, ...} Dim rep() As Byte = _opt.ReplaceBytes If Arrays.CompareTo(rep, _searchparray, 1, False) = -1 AndAlso _opt.Searc

我在VS 2012 RC VB.NET项目中遇到了一个非常奇怪的情况,目标是.NET 2.0。出于某种原因,除了调用属性的Get方法外,还会调用属性的Set方法:

这与预期的效果一样:

Dim _searchparray = New Byte() {37, 115, ...}
Dim rep() As Byte = _opt.ReplaceBytes
If Arrays.CompareTo(rep, _searchparray, 1, False) = -1 AndAlso _opt.SearchMatchPlaceholderInReplaceBytes Then ...
也就是说_opt.ReplaceBytes的Get方法只被调用一次,它的Set方法不被调用

但这不起作用:

Dim _searchparray = New Byte() {37, 115, ...}
If Arrays.CompareTo(_opt.ReplaceBytes, _searchparray, 1, False) = -1 AndAlso _opt.SearchMatchPlaceholderInReplaceBytes Then ...
在这里,首先调用_opt.ReplaceBytes的Get方法,然后调用Arrays.CompareTo返回,然后调用_opt.ReplaceBytes的Set方法!为什么?调用堆栈表明调用方是上面示例中的最后一行!但是它在哪里设置属性呢?它不能在Arrays.CompareTo中,因为Set方法是在函数返回值后调用的,并且也不能通过_opt.SearchMatchPlaceholdinReplaceBytes的Get方法进行设置,因为它的Get方法返回基础字段的值,而不执行其他操作

有人能解释这种奇怪的行为吗? 谢谢

下面是演示这一点的整个示例项目:

Imports System.Runtime.CompilerServices

Module Module1

Sub Main()
    Dim _opt As New Opts
    Dim _searchparray = New Byte() {37, 115}
    If Arrays.CompareTo(_opt.ReplaceBytes, _searchparray, 1, False) = -1 AndAlso _opt.SearchMatchPlaceholderInReplaceBytes Then
        Console.WriteLine("0")
    End If
    Console.WriteLine("1")
End Sub

End Module

Module Arrays

<Extension()> _
Friend Function CompareTo(Of T As IEquatable(Of T))(ByRef SearchArray() As T, ByRef AnotherArray() As T, ByRef aWildCardElement As T, Optional aUseWildcards As Boolean = True) As Integer
    Dim min As Integer = If(SearchArray.Length < AnotherArray.Length, SearchArray.Length, AnotherArray.Length) - 1
    If aUseWildcards AndAlso aWildCardElement IsNot Nothing Then
        For i = 0 To min
            If SearchArray(i).Equals(aWildCardElement) Then Continue For 
            If Not SearchArray(i).Equals(AnotherArray(i)) Then Return i
        Next
    Else
        For i = 0 To min
            If Not SearchArray(i).Equals(AnotherArray(i)) Then Return i
        Next
    End If
    If SearchArray.Length = AnotherArray.Length Then
        Return -1
    Else
        Return min + 1
    End If
End Function

End Module



Public Class Opts

Private _ReplaceBytes() As Byte = New Byte() {}
<Xml.Serialization.XmlIgnore()> _
Public Property ReplaceBytes As Byte()
    Get
        Return _ReplaceBytes
    End Get
    Set(ByVal value As Byte())
        _ReplaceBytes = value
    End Set
End Property

Private _SearchMatchPlaceholderInReplaceBytes As Boolean = False
Public Property SearchMatchPlaceholderInReplaceBytes() As Boolean
    Get
        Return _SearchMatchPlaceholderInReplaceBytes 'Set breakpoint here 
    End Get
    Set(ByVal value As Boolean)
        'Set breakpoint here too
        _SearchMatchPlaceholderInReplaceBytes = value
    End Set
End Property

End Class

Namespace Global.System.Runtime.CompilerServices

<AttributeUsage((AttributeTargets.Method Or (AttributeTargets.Class Or AttributeTargets.Assembly))), System.Reflection.Obfuscation(ApplyToMembers:=True, Exclude:=True)> _
Public NotInheritable Class ExtensionAttribute
    Inherits Attribute
    Public Sub New()
    End Sub
End Class

End Namespace
导入System.Runtime.CompilerServices
模块1
副标题()
Dim_opt作为新选项
Dim_searchparray=新字节(){37115}
如果Arrays.CompareTo(_opt.ReplaceBytes,_searchparray,1,False)=-1,并且还可以在ReplaceBytes中搜索匹配占位符,则
控制台写入线(“0”)
如果结束
控制台写入线(“1”)
端接头
端模块
模块阵列
_
友元函数CompareTo(Of T为i可数(Of T))(ByRef SearchArray()为T,ByRef AnotherArray()为T,ByRef aWildCardElement为T,可选aUseWildcards为Boolean=True)为整数
Dim min As Integer=If(SearchArray.Length
在VB.NET中,当您通过引用传递数组类型的属性时,它似乎会被复制回函数的末尾。这是有意义的,因为通过ByRef传递它意味着引用可能在函数内部发生了更改。因为它是一个通过引用传递的属性,所以我们会影响对属性setter的引用(可能已更改)


解决方案是通过值(ByVal)传递它。您不需要在代码中通过引用传递它。事实上,在大多数情况下,通过值传递比通过引用传递更好。仅当参数还充当返回值时才使用ByRef。

在VB.NET中,当您通过引用传递数组类型的属性时,它似乎会在函数末尾复制回来。这是有意义的,因为通过ByRef传递它意味着引用可能在函数内部发生了更改。因为它是一个通过引用传递的属性,所以我们会影响对属性setter的引用(可能已更改)


解决方案是通过值(ByVal)传递它。您不需要在代码中通过引用传递它。事实上,在大多数情况下,通过值传递比通过引用传递更好。仅当参数还充当返回值时才使用ByRef。

这是ByRef声明和将属性作为参数传递之间的交互。这在C#中是禁止的,但是VB.NET编译器可以解决这个问题

通过声明参数ByRef,您可以告诉编译器您可以修改传递的对象引用。如果将局部变量作为方法参数传递,则当代码指定参数时,该局部变量会得到更新。但是当您传递属性时,这是一个问题,这样的赋值必须调用属性设置器。从而使传递的参数无效。这会导致很难诊断错误

C#编译器只是禁止这样做,因为可能会出现错误。然而,VB.NET编译器通过确保在方法停止执行后调用setter来解决这个问题。这正是您在调试器中看到的。问题是,它总是调用setter,即使您没有修改参数


解决方法很明显,使用ByRef只是一个bug。您的方法实际上没有分配SearchArray参数。参数必须是ByVal。

这是ByRef声明和作为参数传递属性之间的交互。这在C#中是禁止的,但是VB.NET编译器可以解决这个问题

通过声明参数ByRef,您可以告诉编译器您可以修改传递的对象引用。如果将局部变量作为方法参数传递,则当代码指定参数时,该局部变量会得到更新。但是当您传递属性时,这是一个问题,这样的赋值必须调用属性设置器。从而使传递的参数无效。哪个可以