A little confused about class modifiers in VB.NET
In my project i have a BI layer with multiple classes. In each class i have some public methods \ functions that i expose via the public shared modifier.
However in different classes in the BI layer, i need to access methods in a different class, but the same namespace (in the BI layer) that i do not want exposed to the UI project \ layer.
I thought the Friend modifier will expose the method to classes in the same namespace, but it gives me an error saying reference to a non-shared member requires and object reference
Friend modifier (internal in C#) exposes members to classes in the same assembly.
The error in your case is not related to friend modifier. From the error message it seems that you are trying to access instance (i.e. non shared) method as if it was shared method. You need an instance of the class in order to call such methods.
Code sample would be helpful, because it would help to easier tell what should be changed.
Take the following examples.
Instance method
Friend Class Foo
Friend Sub Fubar()
'do something
End Sub
End Class
Usage:
Dim fu As New Foo
fu.Fubar()
Shared method
Friend Class Foo
Friend Shared Sub Fubar()
'do something
End Sub
End Class
Usage:
Foo.Fubar()
Related
I am creating a .dll for a CAD tool I use.
After creating a new project (class library) , I got a "public class-end class" block.
I wrote my main method inside that block. When I run the dll in my CAD tool, its giving me main entry point missing error.
So i come back and change the "public class-end class" ---> "Public Module-end Module".
Now its able to find the main method.
Why is this so? Ive read on these forums that we should not be using modules as much.
If I were to not use modules so much, how I am supposed to make it work without the module block?
VB.Net doesn't have static classes like C# has. Static classes allow you to create static methods such that
class foo
{
void bar() {}
}
Accessed in VB.Net like this
foo.bar()
If you want to create the same functionality with VB.Net you have two options, which are either using a Module
Module foo1
Sub bar()
End Sub
End Module
Class foo2
Shared Sub bar()
End Sub
End Class
However the difference is how Module and Class are scoped. Modules are globally scoped so you can call the module method outside of the originating namespace without qualifying it with the Module name, but to call the static method you need to qualify it with the class name, and even import the namespace in the case of a class with static method
bar()
foo2.bar()
But what Modules are certainly good for is Extension Methods, and the global scope actually helps here if you want to extend a class across your project
Module Extensions
<Extension>
Sub bar(value As String)
End Sub
End Module
Dim s = "my string"
s.bar()
In your case, it's expecting a C# style static class with method, and since VB.Net doesn't have static classes, a Module or class with static method both satisfy that.
Modules come from legacy versions of Visual Basic and sort of act as the "OG" of Visual Basic code files. When Visual Basic 6 and earlier was around, Visual Basic was sort of quasi object oriented and while classes existed, it made more sense to use modules in lieu of static classes. Then when Visual Basic .NET was introduced, Microsoft made a real effort to make the programming language a true object oriented programming language.
People likely tell you to use classes over modules because modules are holdovers from the days prior to Visual Basic being a pure object oriented language. Starting from 2005 on forward, anything you could do in a module could basically be done as a static (aka shared) only class with the exception of extension methods. So by using classes over modules, you're taking a more .NET oriented approach rather than a Visual Basic first approach.
With regards to your specific problem, the issue is that your CAD tool is looking for an entry method, but cannot find one. The simple solution is to add a shared method:
Public Class MyClass
Public Shared Sub Main()
' ...
End Sub
End Class
How do you allow people to implement a class without letting them see or change the code?
Implementation implies Interface. You can just define an Interface in a .NET assembly (.dll) which you provide to said people. There is no implementation in an interface. No code to change other than the property and method names and types.
Public Interface IFoo
Sub Bar()
End Interface
If this code is given to people in a code file, they can change the definition of the Interface.
There is also an abstract class, in VB it is called MustInherit. Other classes can inherit or derive from it (not implement, as your question said, but you might mean this).
Public MustInherit Class Foo
Sub Bar()
Console.WriteLine("Bar")
End Sub
MustOverride Sub Barr()
End Class
If you give this to people in a code file, they can change what happens in Bar() or really do anything they want to it. Again, putting this in a .NET assembly and giving the .dll to people would prevent this from happening. In most cases this is enough to keep people from changing your code.
You can do this by making the output type of your project a class library. This will compile into a .dll file.
Build the project. In the output directory will be a .dll file (if compilation was a success).
You, or other people, could then add a reference to the .dll file created by your class library, in a new project. You could declare a class which implements the public interface defined in it
Public Class MyIFoo
Implements WindowsApplication1.IFoo
Public Sub Bar() Implements WindowsApplication1.IFoo.Bar
End Sub
End Class
And/or make a class which inherits the abstract class you made in the .dll
Public Class MyFoo
Inherits WindowsApplication1.Foo
Public Overrides Sub Barr()
End Sub
End Class
In your new project, you cannot see or change the code of the Interface IFoo or abstract class Foo.
You should use the private keyword to prevent a client of the class from accessing or modifying fields directly. You expose the methods and properties you want the client to access via the public or protected keyword (for inheritance).
As it says on msdn:
Both classes and modules are reference types that encapsulate the items defined within, but they differ in how items are accessed from other procedures.
How is it possible to use a Module inside a Class? How would I access its members and use them?
EDIT #1
I tried to access this module in all possible ways,
Dim memman as MemoryModule
but it gives me an error, Module 'MemoryModule' cannot be used as a type.
From your comment on the question...
Dim memman as MemoryModule
This is incorrect. Modules aren't classes, they can't be instantiated as objects. You can essentially think of a module as being a collection of Shared helper functions. And you'd access those like any other Shared function:
MemoryModule.SomeFunction()
So, for example, if your module looks like this:
Module MemoryModule
Sub PerformAnOperation()
' some function logic
End Sub
End Module
Then any class which can see that module can invoke that function:
MemoryModule.PerformAnOperation()
If logically your "memory module" should be an object capable of separate instances, then it shouldn't be a Module. Instead, you'd want to make it a Class and implement it with instance members instead of Shared members. It's important to structure your code according to the logic and concepts it represents.
I just did some researches on google but I didn't find an answer to my question.
Is there a way to get the list of the active objects (instances of classes) at runtime?
In my application I need to have single instance classes that needs to be used by different running forms but if I create an instance in the form A, ho do i get control of the same instance in the form B?
Thank you
Actually, your question has 2 parts:
1. How to create single-instance objects.
2. How to have the same object accessible from different forms.
Fortunately for you, there is a solution to both of these problems in one simple and common design pattern called Singleton.
Classes written in the Singleton pattern can only have a single instance, and as you are about to see, as a side effect, this instance is accessible through the entire application.
The simplest way to use the singleton design pattern is this:
Public Class SingletonClass
Private Shared _instance As SingletonClass
Public Shared Function GetSingletonClass() As SingletonClass
If isNothing(_instance) Then
_instance = New SingletonClass()
End If
Return _instance
End Function
Private Sub New()
'' Create the instance here
End Sub
End Class
As you can see, since the constructor is private, it is not accessible from anywhere outside of class SingletonClass, and since class SingletonClass holds a static reference to it's instance, it means that every time you write SingletonClass.GetSingletonClass() in your application you get the same instance.
This design pattern solves both of your problems in a simple, elegant, and well known architecture.
Update
I've recently read a great article about different ways to implement singleton patterns. It turns out that my above specific implementation is not so good, as it is not thread safe. The code examples in this article are C#, but it should be very easy to change them to VB.Net. If you are using .Net 4 or higher, I would recommend going with the 6th version - using .NET 4's Lazy type.
It is both thread safe and lazy loading, two advantages that the implementation I've written doesn't have.
I have an overridable sub in my base class
Project1:
Public Class BaseClass
Protected Overridable Sub MySub(ByVal Parameter as MyType)
End Class
Project2:
Public Class DerivedClass
Inherits BaseClass
Protected Overrides Sub MySub(ByVal Parameter as MyType)
End Class
MyType is a type that comes from external COM library. When I'm trying to override it in a derived class, I'm getting
error BC30284: sub 'MySub' cannot be declared 'Overrides' because it does not override a function in a base class
I've added the required COM reference to both projects containing base and derived classes.
Any idea how to get rid of this error? I'm using VS2005 and .NET 2.0
Edit: Every other override is working fine, I'm only getting error if I'm using referenced COM types as parameters. If I change Parameter to Object, overriding works fine.
Have you considered or tried using TlbImp.exe to generate a static DLL from the COM type library, and reference that from both projects (instead of using a COM reference) to make sure they are referring to exactly the same thing? TlbImp is included with Visual Studio, but I can't find it on my system with only Visual Studio Express installed, so if you're using express, you might have to go hunting for it (the linked page may or may not have the version you want). I suspect that if each project has their own COM reference, Visual Studio may be creating a separate COM wrapper for each project and the generated COM wrappers may not entirely agree with each other when it comes to generated GUIDs and whatnot. So by creating a and forcing the use of a single wrapper you may be able to eliminate that as a possible problem.
Rather than using TlbImp, another option is to have a separate project where you encapsulate the MyType in a .NET class and include that project in both your samples.
So you would end up with an intermediate MyDotNetType which would take as a constructor argument Mytype (the COM object) and expose it out as a read-only property.
Then the MySub call, would take the MyDotNetType as an argument.
Kind Regards
Noel
Please check the signature of the Function in both base class and derived class, if you have different agruments or data type o any arguments is not matched. Then you'll get this type of error. Simple please check the function name, argument name and data type. It worked me. I hope this answer will be helpful.
Thanks,
Ramu V