I don't understand how I can pass an argument byref in VB.NET.
I tried this:
Private m_Form As frmMain
Public WriteOnly Property MyForm() As Form
Set(ByRef value As Form)
m_Form = value
End Set
End Property
But VB.NET does not like the "Byref" argument.
Can somebody help?
Thank you!
The ByRef modifier cannot be used in property setters.
It can only be declared in method'ss and constructor's signatures. There it specifies that the underlying variable of an argument can be modified in the called method.
In the following example the ByRef modifier causes the field named "underlyingVariable" to take the new value. By passing the variable by Value, it would not get modified and therefore would be null:
Private underlyingVariable As Object
Public Sub New()
MyMethod(underlyingVariable)
End Sub
Public Sub MyMethod(ByRef o As Object)
o = New Object()
End Sub
You cannot pass things by reference with setters. It must be ByVal. From the VB.NET Specification:
ยง9.7.2 If a parameter list is specified, it must have one member, that member must have no modifiers except ByVal, and its type must be the same as the type of the property.
I don't think it particularly makes sense to use ByRef in a property setter. Using ByRef implies that you may want to change the reference of what invokes the setter.
Form is a reference type (class), so you want to pass it by value. Otherwise you are passing a reference of a reference type.
Related
Basically, the readonly keyword doesn't let me modify a field after I first create the class instance. I could use a property but in this case its just extra overhead. Is there a keyword to make a class field readonly from only outside the class?
make the field private, provide getter and setter for it.
Make the setter private.
This way the value can be seen from outside the class by the getter,but, cannot be set/written from outside the class.
this makes the property read-only from outside the class.
As others have stated, use a property. If you don't want to split the property into one Getter and one Setter then make the setter private.
Public Class Foo
Public Property Abc() As Object
Get
Return Me.m_Abc
End Get
Private Set(value As Object)
Me.m_Abc = value
End Set
End Property
Private m_Abc As Object
End Class
However: The common way is to set the access level of the field to Friend making it accessible within the same assembly, but not from outside the assembly.
Public Class Foo
Public ReadOnly Property Abc() As Object
Get
Return Me.m_Abc
End Get
End Property
Friend m_Abc As Object
End Class
No there isn't. This type is scenario is precisely why properties are provided in the first place. You get a whole lot of flexibility.
However, if you insist you want to use a read only field, you can use reflection to change the value:-
Public Class TestClass
Public ReadOnly MyNumber As Integer
Public Sub New()
'Readonly fields can only be changed this way
'in the constructor
Me.MyNumber = 900
End Sub
Public Sub ChangeNumber(ByVal num As Integer)
SetNumber(num)
End Sub
Private Sub SetNumber(ByVal num As Integer)
Dim fi = Me.GetType.GetField("MyNumber")
'Reflection can change the value of
'a read only field after construction
fi.SetValue(Me, num)
End Sub
End Class
Note that this is a very terrible thing. Reflection shouldn't be used for this sort of thing as you're going to take a performance hit. Just use properties and save yourself the trouble.
I need to pass a ComboBox to a method in a different class module. First I defined the method in the class module as:
Public Sub initializeCombo(ByVal s As String, ByRef c As ComboBox)
And called it from a form:
initializeCombo(s, frmMyForm.cboBox)
This results in a type mismatch. This works if I define the method in the code behind the form, but not in a separate class module.
It's a mismatch because OptionButton is not ComboBox. Try to change it into ByRef c As OptionButton.
You can figure that out by replacing ByRef c As ComboBox with c As Variant, then set a breakpoint on the first line and check on the watch window what is being passed. This usually helps understand what's going on when the object passed is not the expected type.
I have a little problem with an interface. A bunch of my classes implement the ILayoutObject interface. A method declares a variable as ILayoutObject (defaulting it as Nothing) and then runs some code which decides which object it should be. The problem is, the evaluation code runs in a method which receives the variable as a parameter and assigns an object to it. With objects, this would be no problem. The object would be affected by the changes in the method and everything would be OK. Howeverm, when using an interface, the variable in the calling code remains Nothing and behaves like a normal variable. Does anyone have any ideas on how to circumvent that? Alas, due to code structure I am unable to use ByRef or functions :(
Here is some code:
Protected LayoutHandler As Dictionary(Of String, Action(Of Constants.OptionsEntryStructure, ILayoutElements)) = New Dictionary(Of String, Action(Of Constants.OptionsEntryStructure, ILayoutElements)) From
{
{Constants.KeyLayoutType, AddressOf KeyLayoutType}
}
Sub MakeLayOuts
Dim LayoutElement As ILayoutElements = Nothing
Dim Value = "SomeValues"
Dim key = "Key"
LayoutHandler(key)(Value, LayoutElement)
' LayoutElement remains nothing.....
End Sub
Protected Sub KeyLayoutType(elem As Constants.OptionsEntryStructure, Layout As ILayoutElements)
Layout = New LayoutObject 'which would implement the interface
End Sub
You need to declare the parameter as ByRef if you want to alter the object to which the variable in the calling code points to:
Protected Sub KeyLayoutType(elem As Constants.OptionsEntryStructure, ByRef Layout As ILayoutElements)
Layout = New LayoutObject 'which would implement the interface
End Sub
This is true with any reference type (classes). The fact that they are referenced with an interface makes no difference.
If you can't use ByRef, and you can't use a function to return the new object, then your only other real option would be to request a type of object which has the layout object as a property. For instance:
Public Interface ILayoutElementContainer
Public Property LayoutElement As ILayoutElements
End Interface
Protected Sub KeyLayoutType(elem As Constants.OptionsEntryStructure, Container As ILayoutElementContainer)
Container.LayoutElement = New LayoutObject 'which would implement the interface
End Sub
I have been programming for some time, but I have some fundamental questions, one of them is as follows:
Public Class PriceListDetails
Dim pricelist As BSPLib.PriceLists.PriceList
Dim IsReadOnly1 As Boolean
Public Sub New(ByVal IsReadonly2 As Boolean)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
'Readonly prevents from Modifying/Saving
IsReadOnly1 = IsReadonly
End Sub
End Class
Is it compulsory to create IsReadyOnly1 and IsReadyOnly2, is there a way to take the parameter from new method to IsReadyOnly1 Directly like in reference type?
Thank you.
Hard to tell what you mean, the posted code cannot compile. I'll suppose you mean this:
Private IsReadOnly As Boolean
Public Sub New(ByVal IsReadOnly As Boolean)
InitializeComponent()
Me.IsReadOnly = IsReadOnly
End Sub
Where the Me keyword ensures that the field is assigned instead of the parameter.
Setting members with constructor parameters is pretty much common practice in OOP. However, if you are using public properties then you could use object initializers as well:
Dim priceList1 = New PriceListDetails With {.IsReadOnly = True}
Boolean is not reference type variable, so it's not possible.
In case you want to copy the reference,then also you need both variable. You can take only IsReadonly2 as reference.
I have observed a behaviour in VB.net where property setters get called more often than seems necessary, in conjunction 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 to the console the following output
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 spurious call to the property setter following the method execution. I am supposing this behaviour is produced as a safety measure against inadvertently modifying the underlying property, despite this potentially being the intent.
This behaviour in the case of ByRef vs ByVal usage is easily solved by choosing appropriate ByVal keyword, however hase recently noticed a more insidious behaviour, one that has caused a stack overflow of repeated calls, since the setter call would update a value that called the getter only.
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() would fire the AProperty getter method, but then after that usage, would fire the setter method, which by program logic calls DoSomething() again. It is the automatic calling of the setter that puzzles me.
This is, in fact, a feature of VB.Net. In your code, you are passing a property, not a variable, by reference. Strictly speaking, passing a property ByRef 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. Because the method may change the ByRef parameter, which is now the compiler-generated temporary and not your property, the compiler then inserts a call to the setter. Essentially, something like this happens:
Dim temp = Me.ReferenceTypeData
Me.WorkReferenceTypeByReference(temp)
Me.ReferenceTypeData = temp
Other languages, such as C#, do not allow passing a property by reference (rightly so from the strict definition of parameter passing) and instead require you to write the equivalent of the above code yourself.
It is a VB.net "feature". You won't see this in C#. VB.NET will copy an object (in this case, a 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 a parameter value twice: once when entering the method and once when returning from the method. "
So, at the end of method execution, it is basically copying itself, causing the setter to be called.
That said, there is really no point in using ByRef with any object, it's just passing 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.