Pointing to this object vba syntax - vba

I have two class modules. Say class1 and class2. I want to set one of class2's properties to be class1 from within class 1. I know in java you can do something like
Class1{
Set Class2Object= This
}
Class2{
Declare Property as Class1
}
Does vba have an equivalent to "This" from java? Thanks!

in VBA you use Me instead of this
by the way in VBA you use Dim not Declare
and you don't have { and } you simply end it with End Classso your code should look like this
Public Class1
Set Class2.Propertyname = Me
End Class
Public Class2
Dim Propertyname as Class1
End Class
hope this helps

Related

VBA call class property from the class

In a VBA class module (let's say in Excel or Access), I wrote a function SomeFunction() returning a value.
If I call this from another function/sub in the class, should I call it:
a) this way: myVar = SomeFunction or
b) this way: myVar = Me.SomeFunction ?
I think both work, so except for the writing style and clarifying SomeFunction is part of the class, does it make any difference?
Both are indeed valid, but way B should be preferred since it's more explicit what you're doing.
Consider the following (valid) class code:
Public Property Get SomeValue() As Integer
SomeValue = 5
End Property
Public Property Get AnotherValue() As Integer
Dim SomeValue As Integer
SomeValue = 3
AnotherValue = SomeValue 'Returns 3
Debug.Print Me.SomeValue 'Returns 5
End Property
Because you can (but shouldn't) do this in VBA, it's a good practice to use Me. to make it clear you're using a class property and not a variable.
As far as I know - It does not make any difference.
However, if you use Me. in the class, you can use the Intellisense to see the available subs, functions and properties, which could be a bit handy:
However, I prefer not to use the Me.
If you are having the following in a module:
Public Function Foo()
Foo = 5
End Function
Sub TestMe()
Dim cls As New Klasse1
cls.TestMe
End Sub
And then the following in Klasse1:
Sub TestMe()
Debug.Print Modul1.Foo
Debug.Print Me.Foo
Debug.Print Foo
End Sub
Function Foo()
Foo = 10
End Function
it is visible that the existense of Me. is just syntax sugar.

Assign value to instance of current class

I have a class we will call MyClass. Inside I have some deserialization code that I want to be able to call from within the object. Is there a cleaner way to assign the values associated with the class from within the class.
Here is what I am doing now
Public Class MyClass
Public Property Prop1 as New String(String.empty)
Public Property Prop2 as New String(String.empty)
Public Property Prop3 as Boolean = False
Public Sub LoadXML(ByVal XMLText as String)
Dim MyTemp as New MyClass
MyTemp = CType(DeSerialize(XMLText, MyTemp.Type), MyClass) 'this returns an object
Me.Prop1 = MyTemp.Prop1
Me.Prop2 = MyTemp.Prop2
Me.Prop3 = MyTemp.Prop3
End Sub
End Class
I cannot assign the result of MyTemp to Me (which ostensibly represent the same object type) but I can assign all of the properties of MyTemp to the properties of Me. Since my actual class is much more complicated (I used primitives in the example - but in reality is a pretty large class with properties that are many other classes) I wondered if there is a better way to assign the value of MyTemp to the instance of the class.
You probably want to create a Shared function that will return an instance of MyClass in lieu of a constructor.
Public Shared Function LoadXML(ByVal XMLText As String) As MyClass1
Dim MyTemp As New MyClass1
MyTemp = CType(DeSerialize(XMLText, MyTemp.GetType()), MyClass1)
Return MyTemp
End Function
You can run this to create the initial instance of the class, so instead of calling new you would call MyClass.LoadXML(xmlString).
You would probably be a lot better off to declare LoadXML as a shared function that just returned the deserialized object. That way, instead of
dim myClassInstance = new MyClass();
myClassInstance.LoadXML(...)
You would do
dim myClassInstance = MyClass.LoadXML(...);
And you wouldn't need to do all that property copying.
(sorry, VB is rusty)

How do I determine if a class member exists?

I have a public subroutine that is called by many classes. However, I now need to do something in that subroutine that only pertains to a small number of the classes that call it. So instead of going back and adding the property to all of the existing classes, I would like to simply check to see see if that class has that property and if so, then do something with it. But I can't seem to figure out how to simply check for the existence of the member without getting an error.
For example:
Public Class_1
Public a1 as string = ""
Public Sub New()
' when a button is clicked call subroutine "check()"
End Sub
End Class
Public Class_2
Public a1 as string = ""
Public a2 as integer = 0
Public Sub New()
' when a button is clicked call subroutine "check()"
End Sub
End Class
Public Class whatever
Public Sub check(sender as object)
If sender.a2 = 0 then
' do something
End if
End Sub
End Class
I have tried such things as
If not(sender.a2 is nothing) then
If isnothing(sender.a2) then
But I can't get past the fact that I get an error simply by using "sender.a2" since a2 is not always a member of the sender.
How can I check to see if a2 is a member of the sending class without using "sender.a2"?
If you want to see that a field exists you need this:
Dim fi As FieldInfo = sender.GetType().GetField("nameOfFieldHere")
If fi IsNot Nothing
'field exists now get the value
Dim o As Object = fi.GetValue(sender)
End If
Take a look at the documentation Type.GetField Method (String)
There are also overloads available too.
You can test that the Object you are referencing is of a certain type before attempting to use it. Once you've determined it's the right type, you can safely cast to it and then use the right properties like so:
If (TypeOf sender Is Class_2) Then
Dim castObj As Class_2 = CType(sender, Class_2)
'We can now access castObj.a2
End If
If there are multiple classes with the property, it would be sensible to create an Interface which states they have the a2 property and have them all implement it. You can then test their type against the new Interface instead of Class_2.
An alternative option is to use class inheritance to implement a default public method for all classes, and override it in your special Class_2 case for your subclasses.

Declaring global, static variables

I'm trying to set a global variable in Visual Studio, but I can't make it static. Is there any way for me to set the variable as static and share it across different methods, or some way to save the variable each time it changes?
You have two options:
1 - Create a class that contains a Shared variable (this is the same as a static variable in C#)
Public Class GlobalVariables
Public Shared Bar As String
End Class
You can then access this using the class name:
GlobalVariables.Bar = "Hello world"
2 - Create a module (this is akin to a static class in C#)
Public Module GlobalVariables
Public Bar As String
End Module
You can then access this value in code like this:
Bar = "Goodbye cruel world"
If you use the number 1 option presented by #Matt Wilko, you can reference the shared member either through an object instance of the class or by referencing the class without an object reference. Both point to and increment the same variable and therefore reference the same value. Although, the Visual Studio compiler provides a warning about referencing an object instance and says that it will not be evaluated, it still compiles. The compiler's recommendation is to use the class name.
Public Class GlobalVariables
Public Shared Foo As Integer
End Class
Insert the following into a form and call IncrementIntegers() from a button click event procedure and you will find that myGlobalVariables.Foo and GlobalVariables.Foo both return 20.
Private Sub IncrementIntegers()
Dim myGlobalVariables As New GlobalVariables
myGlobalVariables.Foo = 0
GlobalVariables.Foo = 0
myGlobalVariables.Foo += 10
GlobalVariables.Foo += 10
Dim iLocalInt1 = myGlobalVariables.Foo
MessageBox.Show("myGlobalVariables.Foo = " & iLocalInt1.ToString)
Dim iLocalInt2 = GlobalVariables.Foo
MessageBox.Show("GlobalVariables.Foo = " & iLocalInt2.ToString)
End Sub
Note that with option 1, Foo must be qualified with either the class name or an object name. With option 2, it is a module and not a class so an object reference cannot be created. The public variable can be referenced without qualifying it with the module name unless a variable with the same name appears in another module in which case the compiler with throw a name conflict error. For example,
Public Module1
Public Foo As String
End Module
Public Module2
Public Foo As String
End Module
Remove Module2 and Foo can be called unqualified from anywhere.
Foo = "Happy birthday"
With Module2 present, Foo must be qualified with the name as both point to different variable and represent different and independent values.
Module1.Foo = "Goodbye cruel world"
Module2.Foo = "Hello new world"

Script Task : write 2 classes and access Global variable

Can i write 2 classes for one Script Task editor in SSIS(2008). I tried to access the global variable like below. I created 2 classes and it doesn't show any compile error, but i couldn't access the global variable in class2 which was assigned as 2 in class, ScriptMain. Please suggest.
Imports System
Imports System.Data
Class ScriptMain
Dts.Variables("var").Value = 2
End Class
Class class2
Dim var2 As String
var2 = Dts.Variables("var").Value
End Class
Disclaimer - I don't know anything about SSIS, but ...
You can't use Dim statements in the body of a class - they need to be in a method in .net.
There are special methods called constructors (New), that get called when a class is instantiated though, so try
Imports System
Imports System.Data
Class ScriptMain
public sub new()
Dts.Variables("var").Value = 2
end sub
End Class
Class class2
public function GetGlobal() as string
Dim var2 As String
var2 = Dts.Variables("var").Value
return var2
end function
End Class
You'd need to do Dim x as new class2() somewhere and then you can do a call to x.GetGlobal(). Since GetGlobal doesn't make use of any instance state, you could just make it shared.
Beyond that, it's not clear as to what you are trying to accomplish with specificity.