VB.NET 2012属性获取属性集 [英] VB.NET 2012 Property Set on Property Get

查看:173
本文介绍了VB.NET 2012属性获取属性集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在针对.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆