VB.NET 2012属性获取属性集 [英] VB.NET 2012 Property Set on Property Get
问题描述
在针对.NET 2.0的VS 2012 RC VB.NET项目中,我遇到了非常奇怪的情况。由于某种原因,除了其Get方法之外,还调用了属性的Set方法:
这可以按预期工作:
Dim _searchparray = New Byte(){37,115,...}
Dim rep()As Byte = _opt.ReplaceBytes
If Arrays.CompareTo(rep ,_searchparray,1,False)= -1并且_opt.SearchMatchPlaceholderInReplaceBytes然后...
那是_opt .ReplaceBytes的Get方法仅被调用一次,而其Set方法未被调用。
但这不起作用:
Dim _searchparray = New Byte(){37,115,...}
If Arrays.CompareTo(_opt.ReplaceBytes,_searchparray,1,False)= -1 AndAlso _opt.SearchMatchPlaceholderInReplaceBytes然后...
在这里,首先调用_opt.ReplaceBytes的Get方法,然后调用数组.CompareTo返回,然后调用_opt.ReplaceBytes的Set方法!为什么?调用堆栈表明调用者是上面示例中的最后一行!但是,它在哪里设置属性?它不能在Arrays.CompareTo中,因为在函数返回值之后调用Set方法,并且也不能通过_opt.SearchMatchPlaceholderInReplaceBytes的Get方法进行设置,因为它的Get方法返回基础字段的值,并且什么都不做! / p>
有人对这种奇怪的行为有一种解释吗?
谢谢。
以下是演示此操作的整个示例项目:
导入System.Runtime.CompilerServices
模块Module1
Sub Main()
Dim _opt作为新选项
Dim _searchparray =新字节(){37,115}
如果Arrays.CompareTo(_opt.ReplaceBytes,_searchparray,1,False)= -1而且_opt.SearchMatchPlaceholderInReplaceBytes然后
Console.WriteLine( 0)
如果
Console.WriteLine( 1)
End Sub
End Module
模块数组
< Extension()> _
Friend Function CompareTo(Of T as IEquatable(Of T))(ByRef SearchArray()As T,ByRef AnotherArray()As T,ByRef aWildCardElement As T,可选aUseWildcards As Boolean = True)作为整数
作为整数的Dim min = If(SearchArray.Length< AnotherArray.Length,SearchArray.Length,AnotherArray.Length)-1
如果aUseWildcards AndAlso aWildCardElement都不为零,则
对于i = 0要最小化
如果SearchArray(i).Equals(aWildCardElement)然后继续
如果不是SearchArray(i).Equals(AnotherArray(i))然后返回i
下一个
其他
对于i = 0要最小
如果不是SearchArray(i).Equals(AnotherArray(i))然后返回i
下一个
结束如果
如果SearchArray.Length = AnotherArray.Length然后
返回-1
其他
返回min + 1
如果
结束函数
结束模块
公共类选择
私有_ReplaceBytes()由于Byte = New Byte(){}
< Xml.Serialization.XmlIgnore()> _ _
公共属性ReplaceBytes作为Byte()
获取
返回_ReplaceBytes
结束Get
Set(ByVal值作为Byte())
_ReplaceBytes =值
结束集
结束属性
私有_SearchMatchPlaceholderInReplaceBytes布尔值= False
公共属性SearchMatchPlaceholderInReplaceBytes()布尔值
获取
返回_SearchMatchPlaceholderInReplaceBytes'设置断点在这里
End Get
Set(ByVal value as Boolean)
'在这里也设置断点
_SearchMatchPlaceholderInReplaceBytes =值
结束Set
结束属性
结束类
命名空间Global.System.Runtime.CompilerServices
< AttributeUsage((AttributeTargets.Method或(AttributeTargets.Class或AttributeTargets.Assembly))) ,System.Reflection.Obfuscation(ApplyToMembers:= True,排除:= True)> _
公共不可继承类ExtensionAttribute
继承属性
Public Sub New()
End Sub
End Class
End Namespace
这是ByRef声明与传递属性作为参数之间的交互。这在C#中是禁止的,但是VB.NET编译器可以解决此问题。
通过声明参数ByRef,您可以告诉编译器可能修改传递的对象引用。如果您将局部变量作为方法参数传递,那很好,当您的代码分配该参数时,该局部变量会更新。但是,当您传递属性时,这是一个问题,这种分配必须调用属性设置器。反过来会使传递的参数无效。
由于错误的可能性,C#编译器只是禁止这样做。但是,VB.NET编译器通过确保在该方法停止执行后在 之后调用setter来解决该问题。这正是您在调试器中看到的。麻烦的是,即使您不修改参数,它也始终会调用setter。
解决方法很明显,使用ByRef只是一个错误。您的方法实际上并未分配SearchArray参数。该参数必须为ByVal。
I am having a very weird situation in VS 2012 RC VB.NET project targeting .NET 2.0. For some reason the property's Set method is called in addition to its Get method:
This works as expected:
Dim _searchparray = New Byte() {37, 115, ...}
Dim rep() As Byte = _opt.ReplaceBytes
If Arrays.CompareTo(rep, _searchparray, 1, False) = -1 AndAlso _opt.SearchMatchPlaceholderInReplaceBytes Then ...
That is _opt.ReplaceBytes's Get method is called only once, and it's Set method is not called.
But this does not work:
Dim _searchparray = New Byte() {37, 115, ...}
If Arrays.CompareTo(_opt.ReplaceBytes, _searchparray, 1, False) = -1 AndAlso _opt.SearchMatchPlaceholderInReplaceBytes Then ...
Here, first _opt.ReplaceBytes's Get method is called, then Arrays.CompareTo returns and THEN _opt.ReplaceBytes's Set method is called! Why? The call stack indicates that the caller is the last line in the sample above! But where does it set the property? It cannot be in Arrays.CompareTo because the Set method is called after the function returned a value, and it cannot be set via _opt.SearchMatchPlaceholderInReplaceBytes's Get method either, because its Get method returns the value of the underlying field and does nothing else!
Does any one have an explanation for this weird behavior? Thanks.
Here's the entire sample project that demonstrates this:
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
This is an interaction between the ByRef declaration and passing a property as the argument. This is forbidden in C# but the VB.NET compiler works around the problem.
By declaring the argument ByRef, you tell the compiler that you might modify the passed object reference. Which is fine if you pass a local variable as the method argument, that local variable gets updated when your code assigns the argument. But this is a problem when you pass a property, such an assignment would have to call the property setter. Which in turn invalidates the passed argument. Which can cause a very difficult to diagnose bug.
The C# compiler just forbids this due to the bug possibilities. The VB.NET compiler however works around it by ensuring that the setter gets called after the method stops executing. Which is exactly what you saw with the debugger. Trouble is, it always calls the setter, even if you didn't modify the argument.
The workaround is obvious, using ByRef is just a bug. Your method does not actually assign the SearchArray argument. The argument needs to be ByVal.
这篇关于VB.NET 2012属性获取属性集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!