force module namespace qualification - vb.net

VB.net allows you to skip the qualification of a function call with the module name:
Public Module EvalDataFetcher
Public Function JoinStr(ByVal values As IEnumerable(Of String)) As String
' body
End Function
End Module
And then do:
Dim foo As String = JoinStr(myBars)
How to force the users to use the fully qualified form? ie force:
Dim foo As String = EvalDataFetcher.JoinStr(myBars)

If there is a way to force you to specify the module name, I'm not sure what it would be. However, the way you ca do it is to make it a class with shared members rather than a module. For instance:
Public Class EvalDataFetcher
Public Shared Function JoinStr(ByVal values As IEnumerable(Of String)) As String
' body
End Function
End Module
Now, when you call the JoinStr method, you will be forced to specify the class name:
Dim foo1 As String = JoinStr(myBars) ' Won't compile
Dim foo2 As String = EvalDataFetcher.JoinStr(myBars) ' Works

This behavior can be achieved with HideModuleName attribute as workaround - HideModuleNameAttribute
Wrap your module with namespace and add HideModuleName attribute to the module
Namespace Utils
<HideModuleName()>
Friend Module UtilsModule
Public Sub YourMethod(parameter As Object)
'Method code
End Sub
End Module
End Namespace
If namespace will not be added with the Imports in the file, then
you will need to use namespace name and HideModuleName attribute will hide module name from the intellisense
Utils.YourMethod(param)

Related

Shared function that infers the class type and can be returned in a list

I would like to create a shared function that returns a list of instances of the classes type. Currently this is what my code looks like
class MyClass
Implements BusinessObject
Shared Function LoadAll(Of T As {BusinessObject, New})() As IEnumerable(Of T)
Dim helper = New SQLHelper()
Return helper.LoadDataTableFromDatabase("LoadTable", LoadAllProcedureName).Rows.Cast(Of DataRow).Select(Function(s) New T().FillDataRow(Of T)(s))
End Function
End Class
class MyDerivedClass Implements MyClass
End MyClass
When I go to use it, I have to use it like this:
MyDerivedClass.LoadAll(Of MyDerivedClass)()
I would like to be able to infer the type, instead of having to use the (Of MyDerivedClass) so that my code looks like MyDerivedClass.LoadAll().
Any help or keywords that I am missing to achieve this would be greatly appreciated.
Here is an extension method which (theoretically) would work on any class you define:
Public Module Module1
<Extension()> _
Public Function LoadAll(Of T As {BusinessObject, New})(ByVal x As T) As IEnumerable(Of T)
Dim LoadAllProcedureName As String = "LoadAllProcedure"
Dim helper = New SQLHelper()
Return helper.LoadDataTableFromDatabase("LoadTable", LoadAllProcedureName).Rows.Cast(Of DataRow).Select(Function(s) New T().FillDataRow(Of T)(s))
End Function
Public Sub Main()
Dim dC As New DerivedClass()
Dim allDc As IEnumerable(Of DerivedClass) = dC.LoadAll()
'::: Somewhat shorter syntax
Dim allDC As IEnumerable(Of DerivedClass) = (New DerivedClass()).LoadAll()
End Sub
End Module
But, as others have pointed out, this doesn't really clean anything up for you. More to the point, you are going to have to type (Of DerivedClass) in whatever variable you intend on populating with your enumerated DerivedClass, no?
And from what I can tell, you cannot have Shared extension methods -- should you be thinking that is the way to go.

Function [function signature] Statement is not valid in a namespace

I get 2 errors on the following statements when making a keygenerator for XP Repair Pro6:
TextBox2.Text = Generate(Strings.LCase(TextBox1.Text), Strings.LCase(MD5("xprp6-K0Wc0kf3Wcm5g-FEe43f")))
'MD5' is a type and cannot be used as an expression.
Public Shared Function MD5(ByVal InputStr As String) As String
Statement is not valid in a namespace.
How do I fix this?
You defined your MD5 function in a namespace, and that's not valid; functions must be in a Module or Class scope; it's modules and classes that live in namespaces, not functions.
In other words, you have this:
Namespace Some.Namespace
Class Foo
'...code...
End Class
Public Shared Function MD5(ByVal InputStr As String) As String
'...code...
End Function
End Namespace
And you need to have this:
Namespace Some.Namespace
Class Foo
'...code...
Public Shared Function MD5(ByVal InputStr As String) As String
'...code...
End Function
End Class
End Namespace

Can UDT's be used as method parameters in any way?

For years I've been avoiding the use of Public Type UDT's in VBA, because they're hard to pass around and I never really bothered trying to understand why.. until now - it was simply easier to just create a class module and work with actual objects instead.
But recently I gave it a shot, and once I figured they had to be passed ByRef (as an array would), things started to look like I could start using them.
So I defined a Public Type in a standard module, got this compile error:
So I moved the Public Type into a class module, made the class PublicNotCreatable, and then got this compile error:
Here's some code to reproduce the compile error.
Class module "Something":
Option Explicit
' cannot define a public user-defined type within an object module
Public Type TSomething
Foo As Integer
End Type
Public Function Create(ByRef info As TSomething) As Something
End Function
If you move the definition of TSomething to a standard module, you'll get the other compiler error, telling you that the public UDT must be defined in a public object module (i.e. a class module)... which takes you back to square one.
So if you cannot define a Public Type in a class module, why would the compiler throw a fit and even mention "public user defined types defined in public object modules" if such a thing can't legally exist?
Did it work in VB6 and the compiler message is a remnant of that version? Or is the reason somewhere in how COM works? Is it just me or the two error messages are contradicting each other? Or there's something I'm not understanding?
Obviously I'm misusing/abusing UDT's here. So what are they supposed to be used for, if not for passing a "record" to some method?
From standard module it works without any error. Following code threw no error.
Public Type TEST_TYPE
Prop1 As String
End Type
Public Function fTest(ByRef param1 As TEST_TYPE) As String
param1.Prop1 = "Hello from function"
End Function
Public Sub sTest(ByRef param1 As TEST_TYPE)
param1.Prop1 = "Hello from Sub"
End Sub
Public Sub caller()
Dim p As TEST_TYPE
'/Call Sub
Call sTest(p)
MsgBox p.Prop1
'/Call Function
Call fTest(p)
MsgBox p.Prop1
End Sub
One issue with UDT is about Forward referencing. So this will not compile, apart from that It works perfectly fine with standard modules.
Public Type TEST_TYPE
Prop1 As String
Prop2 As TEST_TYPE2 '/ Fails due to Forward referencing. TEST_TYPE2 should be declared before this UDT.
End Type
Public Type TEST_TYPE2
Prop3 As String
End Type
Edit:
However, the work around to use the UDT in class is Friend
VBA Code for Class
'/ Using UDT in VBA-Class
Private Type TEST_TYPE3
Prop3 As String
End Type
Public Sub caller()
Dim p As TEST_TYPE3
p.Prop3 = "Hello from Class"
Call testClassUDT(p)
End Sub
Friend Sub testClassUDT(p As TEST_TYPE3)
MsgBox p.Prop3
End Sub
Here's a Type being passed as a parameter to a class method, and being returned by a class method.
First the class SomeClass (doesn't need to be PublicNotCreatable)
Option Explicit
Sub test(foo As TFooBar)
Dim s As String
s = foo.foo
End Sub
Function ReturnTFoo() As TFooBar
ReturnTFoo.bar = "bar"
ReturnTFoo.foo = " bar"
End Function
And the Module:
Option Explicit
Public Type TFooBar
foo As String
bar As String
End Type
Sub test()
Dim c As SomeClass
Set c = New SomeClass
Dim t1 As TFooBar
Dim t2 As TFooBar
t1.bar = "bar"
t1.foo = "Foo"
c.test t1
t2 = c.ReturnTFoo
End Sub

Error generating service reference in VS 2015

OK, this worked just fine in VS 2013. It's only when I started work anew on the project after my upgrade to 2015 that the problem has showed up.
In a nutshell, I'm unsure how to tell the WCF Proxy Generator to specify a CLR namespace for a property type; apparently this is required now.
Here's my contract:
<ServiceContract>
Friend Interface IService
<OperationContract> Function CheckFiles() As List(Of String)
<OperationContract> Function CreateBackup(AllFiles As List(Of String)) As BackupResult
End Interface
Here's the class being returned:
Public Class BackupResult
Public Property DbService As New DbService
Public Property TmpFolder As System.IO.DirectoryInfo ' <== Problem here '
Public Property Chunks As Integer
End Class
And just for clarity, here's the class for the DbService property (although its only relevance for this question is to show that it doesn't have any System.IO references).
Public Class DbService
Public Property ErrorMessage As String = String.Empty
Public Property HasError As Boolean = False
End Class
My problem is that the proxy generator doesn't seem to be able to see that DirectoryInfo is in the System.IO namespace—it keeps generating it in the service's namespace. (When I comment out the CreateBackup() function, rerun the service and update the reference, the QbBackup.DirectoryInfo class isn't generated. I don't get the warning shown below and everything works—like it did in 2013—but of course without the property I need.)
Here's the generated code:
Namespace QbServer
' ... '
' '
' Other generated code here '
' '
' ... '
' '
' Note the generated DirectoryInfo class and '
' the BackupResult.TmpFolder property of type '
' QbServer.DirectoryInfo, when the namespace '
' should be System.IO instead '
' '
<System.Diagnostics.DebuggerStepThroughAttribute(),
System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0"),
System.Runtime.Serialization.DataContractAttribute(Name:="BackupResult", [Namespace]:="http://schemas.datacontract.org/2004/07/Service"),
System.SerializableAttribute()>
Partial Public Class BackupResult
Inherits Object
Implements System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged
<System.NonSerializedAttribute()>
Private extensionDataField As System.Runtime.Serialization.ExtensionDataObject
<System.Runtime.Serialization.OptionalFieldAttribute()>
Private ChunksField As Integer
<System.Runtime.Serialization.OptionalFieldAttribute()>
Private DbServiceField As QbServer.DbService
<System.Runtime.Serialization.OptionalFieldAttribute()>
Private TmpFolderField As QbServer.DirectoryInfo
<Global.System.ComponentModel.BrowsableAttribute(False)>
Public Property ExtensionData() As System.Runtime.Serialization.ExtensionDataObject Implements System.Runtime.Serialization.IExtensibleDataObject.ExtensionData
Get
Return Me.extensionDataField
End Get
Set
Me.extensionDataField = Value
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()>
Public Property Chunks() As Integer
Get
Return Me.ChunksField
End Get
Set
If (Me.ChunksField.Equals(Value) <> True) Then
Me.ChunksField = Value
Me.RaisePropertyChanged("Chunks")
End If
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()>
Public Property DbService() As QbServer.DbService
Get
Return Me.DbServiceField
End Get
Set
If (Object.ReferenceEquals(Me.DbServiceField, Value) <> True) Then
Me.DbServiceField = Value
Me.RaisePropertyChanged("DbService")
End If
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()>
Public Property TmpFolder() As QbServer.DirectoryInfo
Get
Return Me.TmpFolderField
End Get
Set
If (Object.ReferenceEquals(Me.TmpFolderField, Value) <> True) Then
Me.TmpFolderField = Value
Me.RaisePropertyChanged("TmpFolder")
End If
End Set
End Property
Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Sub RaisePropertyChanged(ByVal propertyName As String)
Dim propertyChanged As System.ComponentModel.PropertyChangedEventHandler = Me.PropertyChangedEvent
If (Not (propertyChanged) Is Nothing) Then
propertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
End If
End Sub
End Class
<System.Diagnostics.DebuggerStepThroughAttribute(),
System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")>
Public Class DirectoryInfo
End Class
End Namespace
And here's the warning I'm getting in Visual Studio 2015:
Custom tool warning: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
Error: ISerializable type with data contract name 'DirectoryInfo' in namespace 'http://schemas.datacontract.org/2004/07/System.IO' cannot be imported. The data contract namespace cannot be customized for ISerializable types and the generated namespace 'QbServer' does not match the required CLR namespace 'System.IO'. Check if the required namespace has been mapped to a different data contract namespace and consider mapping it explicitly using the namespaces collection.
XPath to Error Source: //wsdl:definitions[#targetNamespace='http://tempuri.org/']/wsdl:portType[#name='IService'] ConsoleTest D:\Dev\Customers\OIT\Active\ConsoleTest\Service References\QbServer\Reference.svcmap 1
This all results in the proxy classes not being generated.
I've been reading this and this, but they seem to pertain to custom namespaces at the service level. I need to know how to tell the generator to recognize the property type as a CLR type and NOT generate a DirectoryInfo class of its own.
The class System.IO.DirectoryInfo is not supported by the DataContractSerializer. Instead you could try using the XmlSerializer, but you'll likely run into other issues.
A simple solution is to add a string property which captures the data needed to recreate the correct objects. You can keep the original property as well, just be sure to mark it with the [NonSerialized] attribute.
Alternatively you can use the OnSerializing and OnDeserializing attributes to ensure that the DirectoryInfo value is stored in the string field and so that the DirectoryInfo is restored after deserialization.
For more information see:
https://blogs.msdn.microsoft.com/carlosfigueira/2011/09/05/wcf-extensibility-serialization-callbacks/

How do I call a subroutine from a string variable?

Using VB.Net 4 and VS2012
I have a Module with some logic in it like this:
Module Mod1
If x = 1 then
Mod2("Mod3","save_it")
else
Mod2("Mod4","edit_it")
end if
End Module
Module Mod2(which_mod, which_action)
' call the correct subroutine
which_mod.which_action()
End Module
How do I use the strings to call the correct subroutine from different modules?
Look at the System.Reflection namespace, it contains a class called MethodInfo.
You can obtain the MethodInfo, for a given object, using the method name, then invoke it:
Dim method As MethodInfo = obj.GetType().GetMethod(methodName, BindingFlags.Instance Or BindingFlags.Public)
method.Invoke()
source
There is a function CallByName which does exactly that.
The function accepts 4 parameters:
object/class
function/procname
calltype (CallType.method, CallType.Get, CallType.Set)
(optional): parameter (in arrayformat)
The first parameter (object/class) can't be a string, so we have to cast your string to an object. The best way to do this is
Dim MyInstance As Object = Activator.CreateInstance(Type.GetType(which_mod))
So for your code:
Imports Microsoft.VisualBasic.CallType
Imports System.Reflection
Class Mod1
If x = 1 then
Mod2("Mod3","save_it")
else
Mod2("Mod4","edit_it")
end if
End Class
Module Mod2(which_mod, which_action)
' call the correct subroutine
Dim MyInstance As Object = Activator.CreateInstance(Type.GetType(which_mod))
CallByName(MyInstance , which_action, CallType.Method)
End Module