When after downloads, add project reference to
Microsoft.VisualBasic.Architecture.Framework/+Microsoft.VisualBasic.Architecture.Framework.vbproj
Code Architecture of a VisualBasic CLI program
A special function named main is the starting point of execution for all VisualBasic programs. A VisualBasic CLI application should define the Main entry point in a Module which is named Program and running from a Integer Function Main. By using the name of Program for the entry point module, this will makes more easily recognize of your program's entry point.
Module Program
Public Function Main() As Integer
Return GetType(CLI).RunCLI(App.CommandLine)
End Function
End Module
By using a Integer Function instead of Sub in VisualBasic, this makes your code style is more standard compare with the main function from C++.
int main(int argc, char *argv[]) {
}
Where, the type CLI is the CLI interface which it is a module that contains all of the CLI command of your application. And the extension function RunCLI is a CLI extension method from the VisualBasic App helper: Microsoft.VisualBasic.App. The property value of App.CommandLine is the commandline argument of current application that user used for start this application and calling for some CLI command which is exposed in CLI module.
How to define the CLI module?
A Module is a static Class type in the VisualBasic, and it usually used for the API exportation and common method definition for a set of similarity or functional correlated utility functions.
And then so that the CLI module in the VisualBasic can be explained as: A module for exposed the CLI interface API to your user.
Here is a example:
Partial Module CLI
<ExportAPI("/Print", Usage:="/Print /in <inDIR> [/ext <ext> /out <out.Csv>]")>
Public Function Print(args As CommandLine.CommandLine) As Integer
Dim ext As String = args.GetValue("/ext", "*.*")
Dim inDIR As String = args - "/in"
Dim out As String = args.GetValue("/out", inDIR.TrimDIR & ".contents.Csv")
Dim files As IEnumerable(Of String) =
ls - l - r - wildcards(ext) <= inDIR
Dim content As NamedValue(Of String)() =
LinqAPI.Exec(Of NamedValue(Of String)) <= From file As String
In files
Let name As String = file.BaseName
Let genome As String = file.ParentDirName
Select New NamedValue(Of String)(genome, name)
Return content.SaveTo(out).CLICode
End Function
End Module
This example code can be found at: github
How to expose the CLI interface API in your application?
A wrapper for parsing the commandline from your user is already been defined in namespace:Microsoft.VisualBasic.CommandLine
And the CLI interface should define as in the format of this example:
Imports Microsoft.VisualBasic.CommandLine
Imports Microsoft.VisualBasic.CommandLine.Reflection
<ExportAPI("/Print", Usage:="/Print /in <inDIR> [/ext <ext> /out <out.Csv>]")>
Public Function CLI_API(args As CommandLine) As Integer
Using the VisualBasic CommandLine Parser
For learn how to using the CommandLine Parser, we first lean the syntax of the VisualBasic commandline arguments. A typical commandline arguments in VisualBasic is consist of two parts: 1. Command Name 2. Arguments
Here is a simple example:
App.exe /API1 /test /msg "Hello World!!!" /test2-enable /test3-enable
Where in this CLI, token App.exe is the executable file name of your application; And /API1 token, is the Command Name; And then the last tokens are the parameter arguments, using the commandline in VisualBasic just like function programming in VisualBasic:
Module App
Public Function API1(test As Boolean,
msg As String,
test2Enable As Boolean,
test3Enable As Boolean) As Integer
End Module
You call your CLI command in the console terminal is just like call a function in the VisualBasic Code:
Dim code As Integer = App.API1(True, "Hello World!!!", True, True)
NOTE: There is no order of the VisualBasic CLI arguments, so that all of these CLI examples are equals to each other:
App.exe /API1 /msg "Hello World!!!" /test2-enable /test3-enable /test
App.exe /API1 /msg "Hello World!!!" /test /test2-enable /test3-enable
App.exe /API1 /test /test2-enable /test3-enable /msg "Hello World!!!"
App.exe /API1 /test2-enable /test /test3-enable /msg "Hello World!!!"
Simple Example of VisualBasic CLI application(Example source code at here):
Imports Microsoft.VisualBasic.CommandLine
Imports Microsoft.VisualBasic.CommandLine.Reflection
Module Program
Public Function Main() As Integer
Return GetType(CLI).RunCLI(App.CommandLine)
End Function
End Module
Module CLI
<ExportAPI("/API1",
Info:="Puts the brief description of this API command at here.",
Usage:="/API1 /msg ""Puts the CLI usage syntax at here""",
Example:="/API1 /msg ""Hello world!!!""")>
Public Function API1(args As CommandLine) As Integer
Call Console.WriteLine(args("/msg"))
Return 0
End Function
End Module
Here are some mostly used function in VisualBasic CLI parser for this Example CLI:
App.exe /Test-Example /b /n 52 /xml "~/test.Xml" /num_threads 96 /path "~/tmp/test.log"
Function |
Usage |
Example |
CommandLine.GetBoolean(String) As Boolean |
Get a boolean flag argument from the CLI |
Dim b As Boolean = args.GetBoolean("/b") |
CommandLine.GetInt32(String) As Integer |
Get a parameter value as Integer |
Dim n As Integer = args.GetInt32("/n") |
CommandLine.GetObject(Of T)(String, System.Func(Of String, T)) As T |
Get a parameter string value and then apply a string parser on it for load an .NET object |
Dim x As T = args.GetObject(of T)("/xml", AddressOf LoadXml) |
CommandLine.GetValue(Of T)(String, T, System.Func(Of String, T)) As T |
Get a parameter value, if the parameter is not exist, then default value will be returns, this method is usually used on optional value |
Dim n As Long = args.GetValue("/num_threads", 100L) |
CommandLine.Item(String) As String |
Default readonly property for read string value of a specific parameter |
Dim path As String = args("/file") |
List(Of T) operation in VisualBasic
For enable this language syntax feature and using the list feature in this section, you should imports the namespaceMicrosoft.VisualBasic at first
Dim source As IEnumerable(Of <Type>)
Dim list As New List(of <Type>)(source)
For Add a new instance
list += New <Type> With {
.Property1 = value1,
.Property2 = value2
}
For Add a sequence of new elements
list += From x As T
In source
Where True = <test>
Select New <Type> With {
.Property1 = <expression>,
.Property2 = <expression>
}
if want to removes a specific element in the list
list -= x
Or batch removes elements:
list -= From x As T
In source
Where True = <test>
Select x
Here is some example of the list + operator
Public Function GetDataFrame() As RfamHit() Implements IRfamHits.GetDataFrame
Return hits.ToList(Function(x) New RfamHit(x, Me)) + From x As Hit
In Uncertain
Select New RfamHit(x, Me)
End Function
And using the + operator for add a new object into the list, this syntax can makes the code more readable instead of the poorly readable code from by using method List(of T).Add:
genomes += New GenomeBrief With {
.Name = title,
.Size = last.Size,
.Y = h1
}
genomes.Add(New GenomeBrief With {
.Name = title,
.Size = last.Size,
.Y = h1
})
VisualBasic identifer names
1. Directory type
If possible, then all of the directory path variable can be UPCASE, such as:
Dim DIR As String = "/home/xieguigang/Downloads"
Dim EXPORT As String = "/usr/lib/GCModeller/"
2. Module variable
- All of the module variable should in format like _lowerUpper if the variable is private
- But if the variable is Public or Friend visible, then it should in format like UpperUpper
Here is some example:
Dim _fileName As String
Dim _inDIR As Directory
Public ReadOnly Property FileName As String
Public ReadOnly Property InDIR As Directory
3. Local varaible and function parameter
If possible, all of the local varaible within a function or sub program and the parameters of a function, should be in formatlowerUpper
4. Function And Type name
For Public member function, the function name is recommended in formats UpperUpper, but if the function is Private, Friend, or Protected visible, then your function is recommended start with two underlines, likes __lowerUpper. The definition of the Class, Structure names is in the same rule as function name.
Here is some function name examples(Example picked from here):
Private Function __worker(Of T As I_GeneBrief)(genome As IGenomicsContextProvider(Of T),
getTF As Func(Of Strands, T()),
getRelated As Func(Of T, T(), Integer, T()),
numTotal As Integer,
ranges As Integer) As Density()
Public Function DensityCis(Of T As I_GeneBrief)(
genome As IGenomicsContextProvider(Of T),
TF As IEnumerable(Of String),
Optional ranges As Integer = 10000) As Density()
- Interface type name should start with a upcase character I, like IEnumerable, IList, etc
- Enum type name should end with a lower case character s, like MethodTypes, FormatStyles
At last, for improves of the code readable, try Make your identifier name short enough as possible
String manipulate
1. String.Format
For formatted a string output, then recommended used String.Format function or string interpolate syntax in VisualBasic language. And by using the String.Format function, then format control string is recommended puts in a constant variable instead of directly used in the format function:
Const OutMsg As String = "Hello world, {0}, Right?"
Dim msg As String = String.Format(OutMsg, name)
2. String contacts
For contacts a large amount of string tokens, the StringBuilder is recommended used for this job, not recommend directly using & operator to contacts a large string collection due to the reason of performance issue.
Dim data As Byte() = md5Hash.ComputeHash(input)
Dim sBuilder As New StringBuilder()
For i As Integer = 0 To data.Length - 1
sBuilder.Append(data(i).ToString("x2"))
Next i
Return sBuilder.ToString()
If you just want to contact the string, then a shared method String.Join is recommended used. If the string tokens will be join by a specific delimiter, then using String.Join instead of StringBuilder.Append
Dim tokens As String()
Dim sb As New StringBuilder
For Each s As String In tokens
Call sb.Append(s & " ")
Next
Call sb.Remove(sb.Length -1)
Or just use String.Join, this method is more clean and readable than StringBuilder.Append:
Dim tokens As String()
Dim out As String = String.Join(" ", tokens)
3. String interpolate
The string interpolate syntax in VisualBasic language is recommended used for build SQL statement and CLI arguments as this syntax is very easily for understand and code readable:
Dim SQL As String = $"SELECT * FROM table WHERE id='{id}' AND ppi>{ppi}"
Dim CLI As String = $"/start /port {port} /home {PathMapper.UserHOME}"
So, using this syntax feature makes your code very easy for reading and understand the code meaning, right?
Linq Expression
All of the Linq Expression is recommended execute using LinqAPI if the output type of the expression is a known type:
Appendix
Here are tables of names that i used in my programming, and continues updated....
1.Some common used name for common types
System.Type |
Recommend Name |
Example |
System.Text.StringBuilder |
sb |
Dim sb As New StringBuilder
|
System.String |
s, str, name, sId, id, x |
Dim s As String
Dim str As String
Dim name As String
Dim sId As String
Dim id As String
Dim x As String
|
System.Integer, System.Long |
i, j, n, x |
Dim i As Integer
Dim j As Integer
Dim n As Integer
Dim x As Integer
|
System.Object |
x, o, obj, value |
Dim x As Object
Dim o As Object
Dim obj As Object
Dim value As Object
|
2.Name for some meaning
Meaning |
Recommend Name |
Example |
Commandline arguments |
args, CLI |
Dim args As CommandLine
Dim CLI As String
Dim args As String()
|
SQL query |
SQL, sql, query |
Dim SQL As String = "SELECT * FROM table LIMIT 1;"
|
Iterator |
i, j, k, l |
For i As Integer = 0 to [stop]
For j As Integer = i to [stop]
For k As Integer = j to [stop]
Next
Next
Next
Dim l As Integer = 100
Do while l = 100
Loop
|
Linq query expression |
LQuery |
Dim LQuery = From path As String
In ls -l -r -wildcards("*.Xml") <= DIR
Where InStr(path.BaseName, "xcb") = 1
Select path.LoadXml(Of KEGG.DBGET.Module)
|
Query Result/Function Returns |
result, rtvl |
Dim result As [Module] =
LinqAPI.Exec(Of [Module]) <=
From path As String
In ls -l -r -wildcards("*.Xml") <= DIR
Where InStr(path.BaseName, "xcb") = 1
Select path.LoadXml(Of KEGG.DBGET.Module)
Return result
|