VB.NET 2010, Framework 3.5
Question / problem with global scope in a Windows Service
Barebones Window Service with two default Classes, Class1 and Class2
Class1 looks like this.
Public Class Class1
Public Hi As String = "Hi"
End Class
The main Service Class 'OnStart' below. obj1 looks like it should have global scope
Public Class Service
Public obj1 As New Class1 ' need obj1 to have global scope
Protected Overrides Sub OnStart(ByVal args() As String)
End Sub
End Class
However, trying to access the global obj1 within Class2 generates the error "obj1 is not declared. It may be inaccessible due to its protection level"
Public Class Class2
Public Sub SayHi()
MsgBox(obj1.Hi) ' error here, obj1 is out of scope
End Sub
End Class
In a non-Service app, where Sub Main replaces Sub OnStart, obj1 is visible everywhere. All the other classes can see obj1 until flow goes out of Sub Main.
Does anyone know how to get around this?
This only works in a non service app if the Sub Main is in a module.
The best solution is probably to create a separate class with a shared member
Public Class CommonObjects
Public Shared obj1 As New Class1
End Class
Then you can use obj1 like this:
Public Class Class2
Public Sub SayHi()
MsgBox(CommonObjects.obj1.Hi)
End Sub
End Class
Alternatively just create a module and put Public obj1 As New Class1 in it to use the object without having to specify the fully qualified name
See the answers to this question Classes vs. Modules in VB.NET for more information before deciding which route to take
Related
I have written a VB.NET class that has COM Interop enabled so it can be utilized in VBA - specifically, MS Access.
The class works fine in VB.NET.
With Accees, I can add the reference to it, instantiate the main object and set and return some properties.
But Access does not recognize anything relating to the sub-classes underneath the main class. VB.NET has no problem exposing these classes, but not VBA.
Is this simply a limitation of COM Interop and/or VBA?
Is there a work-around?
No you can’t get interop to generate the sub classes for you (to appear in VBA)
However, keep in mind that nested classes are really the same as non-nested. That sub class instance HAS to be initialized anyway. And there is nothing you can't do if the classes were to be separated. And you can well place many classes in one code module.
So this is purely a syntax preference you are looking for.
However, what you can do declare a pubic instance of any sub class in the main class (variables area as public).
Take this simple example.
Imports System.Runtime.InteropServices
<ClassInterface(ClassInterfaceType.AutoDual)>
Public Class Class1
Private m_Company As String = ""
Public Function MyHello()
MsgBox("Hello world")
End Function
Public Property Company As String
Get
Return m_Company
End Get
Set(value As String)
m_Company = value
End Set
End Property
<ClassInterface(ClassInterfaceType.AutoDual)>
Public Class Class2
Private m_FirstValue As Integer = 2
Public Property V1 As Integer
Get
Return m_FirstValue
End Get
Set(value As Integer)
m_FirstValue = value
End Set
End Property
Public Function MyTimes2() As Integer
Return m_FirstValue * 2
End Function
End Class
End Class
NOTE above the nested class “class2” in above.
Ok, so check the make com assembly visible = True, and for testing check the “register for com interop”
Compile the above, set the reference in Access. (Note how you don’t have to build a custom interface either!!!).
Now, in VBA you get this in intel-sense.
NOTE carefully how the sub class Class2 does not appear.
If you really want the intel-sense and sub class to appear, then to the above vb.net class, simple add this;
Public Class Class1
Private m_Company As String = ""
Public SClass2 As New Class2 <--- add this line to expose as public
Private m_Company As String = ""
.etc. etc. etc.
Now I put a “S” in from of the name – you unfortunately can’t use the same name as the nested class. (so either put something in front of the nested class, or something in front of the public instance of that class (that is what I did in above).
Now if we compile, then in VBA you get this:
Note the class2 DOES appear as a sub class
And if I hit a “dot” in VBA editor, then the sub class methods show like this:
So quite sure the above is the only way to get the sub-classes working with COM interop
I'm currently trying to convert some basics in C# class methods into VB, and I'm having some difficulties.
Say we have two classes, baseClass and newClass
Public Class baseClass
Public Sub New(ByVal obj As Object)
'... do something here
End Sub
End Class
Public Class newClass
Inherits baseClass
Public Sub New(ByVal obj as Object)
'... do something here
End Sub
end Class
However, whenever I tried to declear something like
dim nc as newClass(myObj)
I kept getting an error telling me that
First statement of this 'Sub New' must be a call to 'MyBase.New' or 'MyClass.New' because base class 'baseClass' of 'newClass' does not have an accessible 'Sub New' that can be called with no arguments.
When I was trying to do something like, if written in C#, like this
public partial class newClass : baseClass
{
public newClass(Object obj) : baseClass(obj)
{
// do something here
}
}
I understand that the debugger is telling me just add an empty public sub new() in baseClass, but that's not what I'm trying to do, I wanted it to invoke the other constructor, so hopefully someone can point me in the right direction, since I've been trying to find an easy conversion guide but I couldn't find any.
Any answer is much appreciated.
Public Class newClass
Inherits baseClass
Public Sub New(ByVal obj as Object)
MyBase.New(obj)
End Sub
end Class
I am trying to use a custom class exported as a .tlb in vba. I have done the regasm stuff but I keep getting this error when I try to call a subroutine within the class:
Run-time error '429': ActiveX component can't create object
I've referenced the class in vba, I've built the class for 32bit and 64bit CPUs and nothing worked. Anyways, vba code:
Sub test()
Dim test As New Mail.Class1
test.test
End Sub
And the vb.net code:
Imports System.Runtime.InteropServices
Public Class Class1
Public Sub test()
MsgBox("hello")
End Sub
End Class
That class won't be exposed to COM. Simplest way to do this is to Add New Item and select COM Class. This generates a Class skeleton that looks like this:
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
Public Class ComClass1
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "e19c541f-8eda-4fdd-b030-abed31518344"
Public Const InterfaceId As String = "e2122f92-5752-4135-a416-4d499d022295"
Public Const EventsId As String = "6b03de7e-90d7-4227-90ec-9121c4ce1288"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
End Class
Also remember to check the "Make assembly COM Visible" in the Assembly Information dialog (Project properties>Application tab>Assembly Information)
Now when you compile this and call RegAsm, it should have an entry point for this class
I've got this code:
Public Class Events
Inherits MyModule
Private myTag As MyPoint
'Call Calculations() here!
Public Overrides Sub Calculations()
'Do stuff with myTag
End Sub
End Class
As commented, I need to call Calculations() from class Events. I tried Dim mycalc As New Calculations() but I get
Type 'Calculations' is not defined.
When you do this:
Dim mycalc As New Calculations()
You're not trying to call the Calculations method. You're trying to instantiate the Calculations class. It's not a class, hence the error.
You need to create an instance of the class and then call the method on that instance. Something like this:
Dim myEvents As New Events()
myEvents.Calculations()
Conversely, if you're trying to call the method from within the Events class, you can just call it directly (since the current class instance is already defined):
Calculations()
At the moment I'm trying to create a kind of model in vb.net which can be used to create/fetch database entrys.
I created a main class Model with a shared function to fetch the datasets, e.g. Model.find().
Now I'd like to create Classes which inherit the main Model-Class, e.g. a separate one for users: UserModel.find() => "SELECT * FROM users".
What I need now is to find a way to tell the Class which table it should use. I thought about an abstract String "table" which is a constant in each "child-model", but how could this be implemented as it's not possible to override shared members?
Thanks in advance!
Edit: Maybe this will make it a little clearer what I mean:
Public Class Model
Public Shared _controller As Controller
Public Shared table As String
Protected Shared tableFields As String()
Shared reader As Npgsql.NpgsqlDataReader
Public Shared Function find()
Dim a As ArrayList = New ArrayList
'Test if the tablefields are already known to the class, if not, get them
If tableFields Is Nothing Then
getTableFields()
End If
Dim query As String = "SELECT " + String.Join(", ", tableFields) + " FROM " + table
reader = _controller.executeReader(query)
While reader.Read
o = New Model
Dim v As New Hashtable
For Each field In tableFields
v(field) = reader(field)
Next
o.values = v
a.Add(o)
End While
reader.Close()
Return DirectCast(a.ToArray(GetType(Model)), Model())
End Function
Public values As Hashtable
Public Sub New()
End Sub
End Class
So I want a shared method which finds all database entries and gives back an array of instances of its own type, e.g. Model().
That's why I wanted to keep the find-method shared and not bound to an instance.
I think you could use Generics. Here I´ve pasted an example
All the classes in your domain could inherit from Entity class
Public MustInherit Class Entity
'...
End Class
Your Model class, with your method Find
Public Class Model
Public Shared Sub Find(Of T As Entity)()
' You could know the name of T to find the table
Dim tableName As String = GetType(T).Name
'...
End Sub
End Class
One class of your domain, for example: User class
Public Class User
Inherits Entity
' ...
End Class
And finally, an example of how could you instantiate the Find method
Model.Find(Of User)()
'...
I dunno if this is what you mean, do you find this helpfull?
You could make your main class abstract and each subclass will have to return its "own" table name via its own implementation (e.g. getTableName). This way, you would only have to maintain you method logic in the main class.
It is common to use the Singleton design pattern in such cases: create an instance method, overridden by inheriting classes. Each inheriting class should have that instance method return a Singleton object related to that class.
Here is one way of doing it:
MustInherit Class BaseClass
Public MustOverride Function getTableName() As String
End Class
Class Class1
Inherits BaseClass
Private Shared TableName As String = "myTable1"
Public Overrides Function getTableName() As String
Return TableName
End Function
End Class
Class Class2
Inherits BaseClass
Private Shared TableName As String = "myTable2"
Public Overrides Function getTableName() As String
Return TableName
End Function
End Class
EDIT: a whole different approach.
You can have the base class hold some dictionary, which relates class types (or type names) with the correct table:
Class BaseClass
Private Shared myDictionary As New Collections.Generic.Dictionary(Of Type, String)
Friend Shared Sub RegisterType(ByVal childType As Type, ByVal tableName As String)
myDictionary.Add(childType, tableName)
End Sub
Public Shared Function getTableName(ByVal childType As Type) As String
Return myDictionary.Item(childType)
End Function
End Class
Class Class1
Shared Sub New()
BaseClass.RegisterType(GetType(Class1), "table1")
End Sub
End Class
Class Class2
Shared Sub New()
BaseClass.RegisterType(GetType(Class2), "table2")
End Sub
End Class
Shared (static) objects or object members can't be inherited or overrided. Inheritence is for instance of an object. Since you do not have to instantiate a static class you can't inherit from it. The same with the methods. A static method shouldn't be virtual (Overridable in VB) as it defines a method that perform tasks with no instance of the class. Then this makes it impossible to use instance fields or properties within a static (Shared in VB) method. This is a bad design trying so.
In fact, every static (Shared) classes should be marked as NotInheritable in VB, and defining the default empty constructor only. This is a leak from VB in regards of OOP concepts.