Dynamic properties for classes in visual basic - vb.net

I am a vb.net newbie, so please bear with me. Is it possible to create properties (or attributes) for a class in visual basic (I am using Visual Basic 2005) ? All web searches for metaprogramming led me nowhere. Here is an example to clarify what I mean.
public class GenericProps
public sub new()
' ???
end sub
public sub addProp(byval propname as string)
' ???
end sub
end class
sub main()
dim gp as GenericProps = New GenericProps()
gp.addProp("foo")
gp.foo = "Bar" ' we can assume the type of the property as string for now
console.writeln("New property = " & gp.foo)
end sub
So is it possible to define the function addProp ?
Thanks!
Amit

It's not possible to modify a class at runtime with new properties1. VB.Net is a static language in the sense that it cannot modify it's defined classes at runtime. You can simulate what you're looking for though with a property bag.
Class Foo
Private _map as New Dictionary(Of String, Object)
Public Sub AddProperty(name as String, value as Object)
_map(name) = value
End Sub
Public Function GetProperty(name as String) as Object
return _map(name)
End Function
End Class
It doesn't allow direct access in the form of myFoo.Bar but you can call myFoo.GetProperty("Bar").
1 I believe it may be possible with the profiling APIs but it's likely not what you're looking for.

Came across this wondering the same thing for Visual Basic 2008.
The property bag will do me for now until I can migrate to Visual Basic 2010:
http://blogs.msdn.com/vbteam/archive/2010/01/20/fun-with-dynamic-objects-doug-rothaus.aspx

No - that's not possible. You'd need a Ruby like "method_missing" to handle the unknown .Foo call. I believe C# 4 promises to offer something along these lines.

Related

Difference between a one-line ReadOnly property and a ReadOnly with explicit Get statement in vb.net

I have a simple question.
Is there a difference between a one-line ReadOnly Property and a ReadOnly Property with an explicit Get Statement?
For example, In Visual Studio 2010 I used to have to do this:
Private _Message As String = ""
Public ReadOnly Property Message As String
Get
Return _Message
End Get
End Property
Public Sub New(Message As String)
_Message = Message
End Sub
But now here I am in Visual Studio 2015 and it let's me get away with this:
Public ReadOnly Property Message As String
Public Sub New(Message As String)
Me.Message = Message
End Sub
Now I wasn't trying to me lazy, I just ran across it, expecting IntelliSense to force the Get Statement. So I'm left wondering if there is a difference that I should be aware of. Is it bad practice or does it do something different?
I've managed to find tons of topics and forums about ReadOnly in C#, but I seem to be coming up dry when searching the topic regarding vb.net.
I'll appreciate any input.
Thanks! =)
Properties without explicit getters and setters are simply a syntactic convenience. There's no difference in implementation. You should generally use the second option because it makes your code more readable. Only use the first option if you need extra functionality in the getter.
The accepted answer appears to be untrue, at least for me in Visual Studio 2022.
When a property is not a constant, you have to use the multiline declaration otherwise the initial value is cached
This
Private ReadOnly Property ConnectionFile As String
Get
Return gsapppath & "\connection.txt"
End Get
End Property
returns the correct path whereas this
Private ReadOnly Property ConnectionFile As String = gsapppath & "\connection.txt"
did not include the path because the variable gsapppath was not initialized at the time the class was created, yet it was initialized at the time the property was fetched.
So it's not just a syntactic convenience, there is a functional difference.

Why does Intellisense not work for Default Public Property (sometimes)?

I've had problems with default properties in my code that I can - at least to some extent - reproduce with the following code:
Public Class Dawg
Public Enum DawgEnum
Demo1
Demo2
End Enum
Default Public Property DawgProp(x As DawgEnum) As String
Get
Return "whatever"
End Get
Set(value As String)
'...
End Set
End Property
Public Sub DawgSub()
Me(DawgEnum.Demo1) = "Intellisense works here..."
End Sub
End Class
Public Class DawgTest
Public Sub SomeSub()
Dim d As New Dawg
d(Dawg.DawgEnum.Demo1) = "And here as well..."
End Sub
Public Shared Sub AnotherSub()
Dim d As New Dawg
d(Dawg.DawgEnum.Demo1) = "No help for finding 'Dawg.DawgEnum.Demo1' here..."
d.DawgProp(Dawg.DawgEnum.Demo1) = "...Intellisense helped here..."
End Sub
End Class
The problem being that within the "Shared Sub AnotherSub" when I start typing "d(" Intellisense does not offer me the list of available Enum values for the property.
I also have the problem in other classes that structurally are identical to the class "DawgTest" (a simple public class) where it doesn't work either (within a shared sub or not) - although there are no problems in the test above.
Of course, this isn't a major problem since the code compiles fine and I can always use the explicit property, but it's very annoying and confusing and just like to know, if this is by-design? And, if so: why? If not: how can I fix it?
I can't for sure say, if this problem has been there all along or, if it just came up out of nowhere...
Any thoughts - even 5 cents or less - on the issue would be greatly appreciated :o)

HOW TO Pass VB .NET Arrays Hashes to VBA via COM?

I am currently trying to pass an array of objects as a result to VBA but Excel is complaining the following:
'Function or interface marked as restricted, or the function uses an automation type not supported in Visual Basic.'
I have looked around on the internet and have seen similar issues but not to one I am trying to do.
My function is declared as follows:
<ComClass(Class1.ClassId, Class1.InterfaceId, Class1.EventsId)> _
Public Class Class1
#Region "COM GUIDs"
...
#End Region
Public Sub New()
MyBase.New()
End Sub
Private Const AT_HOME As Boolean = True
Public Function hello() As System.String()
Dim a(10) As String
a(0) = "hello"
a(1) = "Goodbye"
Return a
End Function
Public Function CallArray(ByVal serviceName As String, _
ByVal effectiveDate As String,
ByVal serviceParams() As System.Object,
ByRef ArrayRes() As System.Object) As System.Boolean
VBA is complaining about the System.Objects my question is how the heck are you supposed to pass and return arrays from .NET to VBA. Also the data that will be in the ArrayRes() is mixed type, its not just strings etc, its an array of arrays that can contain strings, integers doubles etc.
I chose VB .NET because I assumed it would be possible to map to VBA easier.
One last thing, if System.Object and Arrays in VB .NET is not the way, ie maybe theres another way via collections or lists, then Im open to that. I just need to get this data into VBA. Also I could move over to C# if needs be.
Thanks for any help or recommendations
Fixed it was the data coming in wasnt in the format needed so I created a function to format and process the data

How to mock a method (custom behavior) with Rhino Mocks in VB.NET

How can I mock one method with RhinoMocks in VB.Net? The reference I found is in C#:
Expect.Call(delegate{list.Add(0);}).IgnoreArguments()
.Do((Action<int>)delegate(int item) {
if (item < 0) throw new ArgumentOutOfRangeException();
});
SharpDevelop converts this to:
Expect.Call(Function() Do
list.Add(0)
End Function).IgnoreArguments().Do(DirectCast(Function(item As Integer) Do
If item < 0 Then
Throw New ArgumentOutOfRangeException()
End If
End Function, Action(Of Integer)))
But that doesn't work either (it doesn't compile).
This is what I want to do: create a new object and call a method which sets some properties of that method. In real-life this method, will populate the properties with values found in the database. In test, I would like to mock this method with a custom method/delegate so that I can set the properties myself (without going to the database).
In pseudo-code, this is what I'm trying to do:
Dim _lookup As LookUp = MockRepository.GenerateMock(Of LookUp)()
_luvalue.Expect(Function(l As LookUp) l.GetLookUpByName("test")).Do(Function(l As LookUp) l.Property = "value")
Unfortunately you're attempting to do both a Sub lambda and a Statement Lambda. Neither are supported in VS2008 (but will be in the upcoming version of VS). Here is the expanded version that will work for VB
I'm guessing at the type of m_list
Class MockHelper
Dim m_list as new List(Of Object)
Public Sub New()
Expect(AddressOf CallHelper).IgnoreArguments().Do(AddressOf Do Hepler)
End Sub
Private Sub CallHelper()
m_list.Add(0)
End Sub
Private Sub DoHelper(ByVal item as Integer)
if item < 0 Then
Throw New ArgumentOutOfRangeException
End If
End Sub
End Class
I have never mocked something w/ both a delegate and a lambda so I can't give a full solution to this problem, but I did want to share some example code for the usual "AssertWasCalled" function in Rhino Mocks 3.5 for vb developers because I spent some time trying to grok this... (keep in mind the below is kept simple for brevity)
This is the method under test - might be found inside a service class for the user object
Public Sub DeleteUserByID(ByVal id As Integer) Implements Interfaces.IUserService.DeleteUserByID
mRepository.DeleteUserByID(id)
End Sub
This is the interactive test to assert the repository method gets called
<TestMethod()> _
Public Sub Should_Call_Into_Repository_For_DeleteProjectById()
Dim Repository As IUserRepository = MockRepository.GenerateStub(Of IUserRepository)()
Dim Service As IUserService = New UserService(Repository)
Service.DeleteUserByID(Nothing)
Repository.AssertWasCalled(Function(x) Wrap_DeleteUserByID(x))
End Sub
This is the wrap function used to ensure this works w/ vb
Function Wrap_DeleteUserByID(ByVal Repository As IUserRepository) As Object
Repository.DeleteUserByID(Nothing)
Return Nothing
End Function
I found this to be a very nasty solution, but if it helps someone w/ the same issues I had it was worth the time it took to post this ;)

Proper usage of array as field member in VB 2005

I normally use C# and I'm attempting to convert a qbasic programmer to the joys of object oriented programming by easing him into VB 2005.
Below is a extremely simplified version of what I'm trying to accomplish. It successfully compiles, but all members in the array of card objects are set to "Nothing". The test line throws a NullReferenceException. What am I doing wrong?
Sub Main()
Dim deck1 As New Deck
Console.WriteLine("Test: " & deck1.cards(2).face)
End Sub
Class Card
Public face As String
Sub New()
face = "Blank"
End Sub
End Class
Class Deck
Public cards(51) As Card
End Class
Yes, when you create an array in .NET, every element of the array is set to the default value of the element type - which is null/Nothing for classes.
You need to populate the array before you use it (or expect it to be full of null references).
Note that this would have behaved exactly the same way in C#.
EDIT: As no-one's actually posted population code that would work yet, here it is:
Class Deck
Public cards(51) As Card
Public Sub New()
For i As Integer = 0 To cards.Length-1
cards(i) = New Card()
Next
End Sub
End Class
You need to do some sort of
For Each currentItem As String in Me.face
currentItem = "Blank"
End
Apologies if the syntax of the for-each is off, I'm a C# guy normally. But the basic issue is that you haven't initialized each element of the array.