Why are property setters called more often than expected?

I have observed behavior in VB.net where property definition tools are called more often than it seems necessary, combined with calls to the sister setter method.

Public Class Form1 Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Console.WriteLine("Calling WorkReferenceTypeByReference") WorkReferenceTypeByReference(ReferenceTypeData) Console.WriteLine("Called WorkReferenceTypeByReference") Console.WriteLine("Calling WorkReferenceTypeByValue") WorkReferenceTypeByValue(ReferenceTypeData) Console.WriteLine("Called WorkReferenceTypeByValue") End Sub Public Sub WorkReferenceTypeByReference(ByRef ref As Point) Dim b As Point = New Point(4, 4) + ref Console.WriteLine(" adding (4,4) to " & ref.ToString) End Sub Public Sub WorkReferenceTypeByValue(ByVal ref As Point) Dim b As Point = New Point(4, 4) + ref Console.WriteLine(" adding (4,4) to " & ref.ToString) End Sub Private m_ReferenceType As Point = New Point(0, 0) Public Property ReferenceTypeData As Point Get Console.WriteLine(" Calling ReferenceTypeData getter") Console.WriteLine(" returning: " & m_ReferenceType.ToString) Return m_ReferenceType End Get Set(ByVal value As Point) Console.WriteLine(" Calling ReferenceTypeData setter") Console.WriteLine(" value = " & value.ToString) m_ReferenceType = value End Set End Property End Class 

The previous code returns the following output to the console

 Calling WorkReferenceTypeByReference Calling ReferenceTypeData getter returning: {X=0,Y=0} adding (4,4) to {X=0,Y=0} Calling ReferenceTypeData setter value = {X=0,Y=0} Called WorkReferenceTypeByReference Calling WorkReferenceTypeByValue Calling ReferenceTypeData getter returning: {X=0,Y=0} adding (4,4) to {X=0,Y=0} Called WorkReferenceTypeByValue 

Note the fake call of the property setting tool after the method is executed. I assume that this behavior is produced as a security measure against unintentional changes to the underlying property, despite the fact that this is potentially an intention.

This behavior when using ByRef vs ByVal can be easily solved by choosing the appropriate ByVal keyword, but the latter recently noticed a more insidious behavior that caused the callback stack to overflow, because the setter call updated the value, which is called only the recipient.

 Public Sub DoSomething() Dim a As New CustomObject(anotherObject.AProperty(getterArgument)) End Sub Public Class AnotherObject Public Property AProperty as SomeType Get ' Get value End Get Set ' Set value, call DoSomething End Set End Property End Class 

In the previous example, calling DoSomething () starts the getproperty AProperty method, but then after this use it starts the setter method, which programmatically calls DoSomething () again. This is an automatic setter call that puzzles me.

+4
source share
2 answers

This is essentially a feature of VB.Net. In your code, you pass a property, not a variable, by reference. Strictly speaking, passing a ByRef property is not possible because ByRef needs a reference to a variable. However, the compiler automatically creates a temporary local on your behalf and passes it to the method for you. Since the method can change the ByRef parameter, which is now the compiler created, and not your property, the compiler then inserts a setter call. Essentially, something similar happens:

 Dim temp = Me.ReferenceTypeData Me.WorkReferenceTypeByReference(temp) Me.ReferenceTypeData = temp 

Other languages, such as C #, do not allow passing a property by reference (this is true due to the strict definition of parameter passing), and instead you will need to write the equivalent of the above code yourself.

+6
source

This is the function of VB.net. You will not see this in C #. VB.NET will copy the object (in this case, the pointer) twice when you use ByRef. See http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/bc54294f-785a-467b-96ec-12d0387074e9/

"As far as I understand VB.NET, ByRef copies the parameter value twice: once when entering the method and once when returning from the method."

So, at the end of the method execution, it basically copies itself, causing a setter call.

However, there is no point in using ByRef with any object, it just passes the pointer anyway when you use ByVal, so the effect of being able to modify the object is the same. ByRef is only useful for value types.

+1
source

All Articles