Vb.Net scoping question - private fields - vb.net

I have been looking at a class that has a method that accepts a parameter that is of the same type of the class containing the method.
Public Class test
private _avalue as integer
Public Sub CopyFrom(ByVal from as test)
_avalue = from._avalue
End Sub
End Class
When used in code
a.CopyFrom(b)
It appears that instance "a" has visibility to the private members of the passed in instance "b" and the line
_avalue = from._avalue
runs without error copying the private field from one object instance to the other.
Does anyone know if this is by design. I was under the impression that a private field was only accessible by the instance of the object.

The private scope is related to the type not the instance. So yes, this is by design.
The class test has knowledge about the private parts of itself, so it can use those parts also on other instances of the same type.

You are writing something similar to to a copy constructor.
Since the copying method/function is being written inside of the same class, it will have access to private variables of any instance of its own class.

Related

Reference to a non-shared member requires an object reference in VB.net

I have a VB.net program that I got from someone else. It is comprised of a main form and 6 other modules (all .vb files). These files all have a "VB" icon next to them in the Explorer pane. I am trying to make a call to a sub-routine in one of the modules from the main form. My line of code is:
QuoteMgr.StartGettingQuotesLevel2(sSym)
where QuoteMgr is the name of the module and StartGettingQuotesLevel2(sSym) is the name of the sub-routine. When I enter this, I get the error message:
Reference to a non-shared member requires an object reference.
The sub-routine is defined in the QuoteMgr Module as follows:
Public Sub StartGettingQuotesLevel2(ByVal oSymbol As String)
What is strange is when I enter:
QuoteMgr.
(the name of the module with a period), it does not show me all the sub-routines and functions in the module. It only shows:
Update_Level1
Update_Level12
Update_Level2
These are Public Const in the module.
Can you tell me what I need to do?
What the compiler is trying to tell you with this error message
Reference to a non-shared member requires an object reference
is that the StartGettingQuotesLevel2 subroutine is an instance method not a shared or class method, see a more detailed explanation here
To call an instance method, you need to have an object instance to call it on. In your case, an object instance of the class type QuoteMgr. Like in the example below:
' create a new QuoteMgr object instance
Dim myQuoteMgr As QuoteMgr = New QuoteMgr()
' call its instance method with "abc" as its oSymbol argument.
myQuoteMgr.StartGettingQuotesLevel2("abc")
It is possible that you only want a single QuoteMgr object instance to be created and used by your main form. In that case, you can make it a member variable of your main form and create it once.
Public Partial Class MainForm
' Create it as a private member variable of the main form
Private m_QuoteMgr As QuoteMgr = New QuoteMgr()
' Use it when "some" button is pressed
Private Sub btnSome_Click(sender As Object, e As EventArgs) Handles btnSome.Click
m_QuoteMgr.StartGettingQuotesLevel2(txtSymbol.Text)
' And possibly do something with the results.
End Sub
End Class
Also, if instances of your QuoteMgr class depend on other object instances for their tasks, you will have to supply these to the constructor method of the QuoteMgr class as the arguments for its constructor's method parameters. Constructors (Sub New(...)) look like this:
Public Class QuoteMgr
' This is a constructor that takes two arguments
' - oMainSymbol: a string value
' - oKernel: an instance of the type Kernel
Public Sub New(oMainSymbol As String, ByRef oKernel As Kernel)
' ....
End Sub
End Class
That means, that when you create a QuoteMgr instance, you have to call its constructor method with the things it need, for example
' There must be an instance of Kernel created somewhere.
Dim myKernel As Kernel = ....
' create a new QuoteMgr object instance with these arguments:
' - oMainSymbol = "SYMABC"
' - oKernel = myKernel
Dim myQuoteMgr As QuoteMgr = New QuoteMgr("SYMABC", myKernel)
Some other recommendations
The explanations I have provided, are about basic VB.NET language features (e.g. the terms highlighted in bold). I suggest that before you make any changes to the code you have, you (1) make a backup of it, and (2) try to read a tutorial and practice on something smaller.
The compiler is (virtually) always right. When it gives you an error message, read it carefully, it will indicate the line where something is wrong and a message that tells you what it needs or is missing.
It is not the purpose of Stack Overflow to provide tutorials or code. It is a Q&A site where the best questions and answers deal with specific, delineated programming problems, for which succinct answers are possible.
Right click your application and go to Properties.
Make sure your application type is "Windows Forms Application".
It means that the routine you are trying to call needs to reference an instance of the form to access the routine. You can either reference an instance as Alex says, or you can make the routine 'Shared', so it doesn't need an instance. To do this, change the definition in QuoteMgr.vb to
Friend Shared Sub StartGettingQuotesLevel2(ByVal oSymbol As String)
Switching it to `Shared' may start showing compiler errors, if the routine accesses form controls or module-level variables. These will need to be added to the parameter list.

Whats the difference between these two initialization methods for a class member in VB.Net?

Whats the difference between these two initialization methods for obj? I've seen both of these, but know know if there is an appropriate time to use one vs the other. I found this post which covers C#, but not sure if the same applies to VB.Net.
Public Class Class1
Sub New()
End Sub
Dim obj As New Object
End Class
vs
Public Class Class1
Sub New()
obj=New Object
End Sub
Dim obj As Object
End Class
My apologies ahead of time if this a duplicate.
In this case, there is no difference. The main difference would be if your constructor does other operations -
In that case, the inline initialization (Dim obj As New Object) will occur prior to any code inside the constructor. Putting the initialization in the constructor lets you choose the order of initialization.
Virtually nothing is different about these samples. In both cases you get the following order of operations
Constructor for Class1 is called
Base constructor (Object in this case) is called
Field obj is assigned a value
In all likely hood it results in identical IL being generated.
Your first version is "declarative". The advantages of it are:
It is easier to see how an field as initialized, as you don't have to look for it in the constructor.
If you have multiple constructors you don't need to repeat yourself.
Your first version is "imperative". The advantages of it are:
You control exactly when it gets created.
You can have different versions for each constructor.
I personally default to declarative style code whenever possible.

Does instantiating and initializing work only when tied to button click?

Beginner question. How come I can do this:
Public Class Form1
Private StudentsInMyRoom As New ArrayList
Public Class student
Public name As String
Public courses As ArrayList
End Class
Private Sub btnCreateStudent_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreateStudent.Click
Dim objStudent As New student
objStudent.name = "Ivan"
objStudent.courses = New ArrayList
StudentsInMyRoom.Add(objStudent)
End Sub
End Class
But I CANNOT do this:
Public Class Form1
Private StudentsInMyRoom As New ArrayList
Public Class student
Public name As String
Public courses As ArrayList
End Class
Dim objStudent As New student
objStudent.name = "Ivan"
objStudent.courses = New ArrayList
StudentsInMyRoom.Add(objStudent)
End Class
In the second example, all of the objStudent.etc get squiggly underlined and it says "declaration expected" when I hover over it. It's the same code except now it is not tied to clicking a button. Can't figure out what is the difference.
It's because the implementation needs to be in a method, the way you have it means the code couldn't possibly be executed, how would you reference this code from elsewhere?
It doesn't have to be tied to a click however:
Private Sub AnyNameYouLike
Dim objStudent As New student
objStudent.name = "Ivan"
objStudent.courses = New ArrayList
StudentsInMyRoom.Add(objStudent)
End Sub
Will work.
Rather than tell you how to fix this code directly, I'm going to explain what I think is going wrong with your thought process, so you can also do a better job writing code in the future.
What I see here is a simple misunderstanding for someone new to programming of how classes work. When you build and define a class, you are not (yet) allocating any memory in the computer, and you are not yet telling the computer to do anything. All you are doing is telling the computer about how an object might look at some point in the future. It's not until you actually create an instance of that class that anything happens:
Public Class MyClass
Public MyField As String
End Class
'Nothing has happened yet
Public myInstance As New MyClass()
'Now finally we have something we can work with,
' but we still haven't done anything
myInstance.MyField = "Hello World"
'It's only after this last line that we put a string into memory
Classes can only hold a few specific kinds of things: Fields, Properties, Delegates (events), and Methods (Subs and Functions). All of these things in the class are declarations of something, rather than the thing itself.
Looking at your samples, the code from your second example belongs inside of a method.
If you want this code to run every time you work with a new instance of your class, then there is a special method, called a constructor, that you can use. That is declared like this:
Public Class MyClass
Public MyField As String
'This is a constructor
Public Sub New()
MyField = "Hello World"
End Sub
End Class
However, even after this last example you still haven't told the computer to do any work. Again, you must create an instance of the class before the code in that constructor will run.
This is true of all code in all .Net programs anywhere. The way your program starts out is that the .Net framework creates an instance of a special object or form and then calls (runs) a specific method in that form to sort of get the ball rolling for your program. Everything else comes from there.
Eventually you will also learn about Shared items and Modules, that can (sort of) break this rule, in that you don't have to create an instance of the object before using it. But until you are comfortable working with instances, you should not worry about that too much.
Finally, I want to point out two practices in your code that professional programmers would consider poor practice. The first is ArrayLists. I can forgive this, because I suspect you are following a course of study that just hasn't covered generics yet. I only bring it up so you can know not to get too attached to them: there is something better coming. The second is your "obj" prefix. This was considered good practice once upon a time, but is no longer fashionable and now thought to be harmful to the readability of your code. You should not use these prefixes.

Curious question - Interface Variables (ie dim x as Iinterface = object?) And also if object is a form

vb.net windows forms question.
I've got 3 forms that have exactly the same functions, so I decided to create an interface.
public Interface IExample
public sub Add()
Public sub Edit()
Public sub View()
End Interface
Then I created the 3 forms, and added the 'implements interface IExample' to each.
public class frmExample1
implements Interface IExample
Same for frmExample2, frmExample3
Finally, in code, I declare a variable of the interface type ..
Dim objfrmExample as IExample
then ...
objFrmExample = frmExample2
At this point, objfrmExample is now instantiated, even though I've not done a "objfrmExpample = new [what-goes-here?] " and I'm curious as to why.
I could possibly guess that because you cannot instantiate an interface variable, then vb.net automatically creates an instance. But thats just a guess. The question is , what is meant by declaring a variable of type Interface, and how does it work?
Anyway, just curious :-)
At this point, objfrmExample is now instantiated, even though I've not done a "objfrmExpample = new [what-goes-here?] " and I'm curious as to why.
This has nothing to do with interfaces. You can always treat a form class name in VB as though it were an instance. The reason is that the VB compiler creates properties of all your forms inside My.Forms. Now you can access a “default” instance of each form by accessing My.Forms.<FormName>.
Now comes the ugly part: you can also omit My.Forms.. In other words, whenever you write just FormName and from the context it’s unambiguous that you need an instance rather than the class name, VB will act as though you’d written My.Forms.<FormName>.
Luckily, this only works for forms, not for any other classes. VB creates each default instance when you first access it. So as long as you don’t access a default instance, it’s not created. Once you access it for the first time, VB creates it and invokes its constructor.
When you declare a variable of type interface you can work with any object that implements the interface. Therefore when setting a variable that is of an interface type equal to a class that implements the interface an implicit cast is done. For example.
Dim oExample as IExample
dim testForm as MyTestForm
oExample = MyTestForm
Now, this is the way that you do it, you can do an explicit cast this way
Dim oExample as IExample
Dim testForm as MyTestForm
oExample = CType(MyTestForm, IExample)
For your specific example with VB.NET and an un-instantiated form this is due to a VB "feature" that auto-creates an instance of the form.

Shared method in VB.NET cannot handle this why?

(I tried with this question but this code isolates the problem better.)
I have this code:
Public Shared Sub PopulateTextFields(ByRef stuffList As List(Of Stuff))
Dim aStuff As New Stuff
For Each aStuff In stuffList
DoStuff(aStuff)
Next
End Sub
Private Sub DoStuff(ByRef theStuff as Stuff)
....
End Sub
I get the following error highlighting DoStuff(aStuff):
Cannot refer to an instance member of
a class from within a shared method or
shared member initializer without an
explicit instance of the class.
Didn't I get an explicit instance of Stuff when I wrote the Dim statement?
Don't understand what's wrong. Thanks in advance!
I think the problem lies with the Subroutine DoStuff. If both your subs lie in the same class, you are trying to refer to DoStuff from within PopulateTextFields, which is a shared sub.
In order to achieve this, you need to declare DoStuff as Shared as well.
Yes you did, but you aren't referencing aStuff you are trying to call it on the static implementation of the class, furthermore you are resetting aStuff to a separate instance through each loop iteration.. change your code to:
Public Shared Sub PopulateTextFields(ByRef stuffList As List(Of Stuff))
Dim aStuff As New Stuff
For Each aStuff In stuffList
aStuff.DoStuff(aStuff)
Next
End Sub
Private Sub DoStuff(ByRef theStuff as Stuff)
....
End Sub
And it should work, but maybe not as expected, I don't really know your intent of having a private member that handles changing a separate reference of it's own type.
It may be appropriate to change the signature of DoStuff to:
Private Sub DoStuff()
....
'Use the Me reference here to change myself
....
End Sub
and then call it as:
aStuff.DoStuff() 'Will modify this instance
You didn't share which type these methods belong to. From your confusion, I'm guessing it's part of the "Stuff" class. But it doesn't really matter. It sounds like you're forgetting one of two things:
Creating an instance of the type in the shared method doesn't somehow attach the shared method to that instance. You could create 10 or 1000 instances in the method, after all.
Passing an instance as a parameter doesn't associate the function with an instance. A parameter is not a call site.
Either way, it comes down to providing an instanced call site. Your DoStuff function is not shared, and so the compiler thinks it needs access to state provided by a specific instance of your type. That instance is the method's call site. You either need an instance of the type to call it from: SomeInstance.DoStuff(aStuff) , or if the method doesn't really need access to any type state you need to mark it shared and call it like this: Stuff.DoStuff(aStuff)