Microsoft VisualBasic 的代码风格指南
Microsoft VisualBasic 的代码风格指南
- 下载最新的 VisualBasic 语言特性运行时
- 或通过 nuget 安装:PM> Install-Package VB_AppFramework
下载后,将项目引用添加到
Microsoft.VisualBasic.Architecture.Framework/+Microsoft.VisualBasic.Architecture.Framework.vbproj
VisualBasic CLI 程序的代码架构
一个名为 main 的特殊函数是所有 VisualBasic 程序的执行起点。VisualBasic CLI 应用程序应该在一个名为 Program 的模块中定义 Main 入口点,并从一个 Integer Function Main 运行。通过为入口点模块使用 Program 名称,可以更容易识别程序的入口点。
Module Program
''' <summary>
''' This is the main entry point of your VisualBasic application.
''' </summary>
''' <returns></returns>
Public Function Main() As Integer
Return GetType(CLI).RunCLI(App.CommandLine)
End Function
End Module
在 VisualBasic 中使用 Integer Function 而不是 Sub,这使得您的代码风格与 C++ 中的 main 函数相比更加标准化。
int main(int argc, char *argv[]) {
// blablabla...
}
其中,类型 CLI 是一个模块,包含您应用程序的所有 CLI 命令的 CLI 接口。扩展函数 RunCLI 是 VisualBasic App 帮助器中的一个 CLI 扩展方法:Microsoft.VisualBasic.App。App.CommandLine 的属性值是用户用于启动此应用程序并调用 CLI 模块中公开的一些 CLI 命令的当前应用程序的命令行参数。
如何定义 CLI 模块?
Module 是 VisualBasic 中的静态 Class 类型,通常用于 一组相似或功能相关的实用函数的 API 导出和通用方法定义。
因此,VisualBasic 中的 CLI 模块可以解释为:一个用于向用户公开 CLI 接口 API 的模块。
这是一个示例
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
此示例代码可在:github 找到
如何在您的应用程序中公开 CLI 接口 API?
用于解析用户命令行的包装器已在命名空间中定义:Microsoft.VisualBasic.CommandLine
并且 CLI 接口应按此示例的格式定义
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
使用 VisualBasic 命令行解析器
为了学习如何使用命令行解析器,我们首先学习 VisualBasic 命令行参数的语法。VisualBasic 中典型的命令行参数由两部分组成:1. 命令名称 2. 参数
这是一个简单的例子
App.exe /API1 /test /msg "Hello World!!!" /test2-enable /test3-enable
在此 CLI 中,标记 App.exe 是您应用程序的可执行文件名;/API1 标记是 命令名称;然后最后几个标记是参数,在 VisualBasic 中使用命令行就像在 VisualBasic 中进行函数式编程一样
Module App
Public Function API1(test As Boolean,
msg As String,
test2Enable As Boolean,
test3Enable As Boolean) As Integer
End Module
您在控制台终端中调用 CLI 命令就像在 VisualBasic 代码中调用函数一样
Dim code As Integer = App.API1(True, "Hello World!!!", True, True)
注意: VisualBasic CLI 参数没有顺序,因此所有这些 CLI 示例彼此相等
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!!!"
VisualBasic CLI 应用程序的简单示例(示例源代码在此处)
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
以下是此 示例 CLI 中 VisualBasic CLI 解析器的一些常用函数
App.exe /Test-Example /b /n 52 /xml "~/test.Xml" /num_threads 96 /path "~/tmp/test.log"
函数 | 用法 | 示例 |
CommandLine.GetBoolean(String) As Boolean | 从 CLI 获取布尔标志参数 | Dim b As Boolean = args.GetBoolean("/b") |
CommandLine.GetInt32(String) As Integer | 将参数值获取为 Integer | Dim n As Integer = args.GetInt32("/n") |
CommandLine.GetObject(Of T)(String, System.Func(Of String, T)) As T | 获取参数字符串值,然后对其应用字符串解析器以加载 .NET 对象 | Dim x As T = args.GetObject(of T)("/xml", AddressOf LoadXml) |
CommandLine.GetValue(Of T)(String, T, System.Func(Of String, T)) As T | 获取参数值,如果参数不存在,则返回默认值,此方法通常用于可选值 | Dim n As Long = args.GetValue("/num_threads", 100L) |
CommandLine.Item(String) As String | 用于读取特定参数字符串值的默认只读属性 | Dim path As String = args("/file") |
VisualBasic 中的 List(Of T) 操作
要启用此语言语法特性并使用此部分中的列表特性,您应该首先导入命名空间 Microsoft.VisualBasic
Dim source As IEnumerable(Of <Type>)
Dim list As New List(of <Type>)(source)
用于添加新实例
list += New <Type> With {
.Property1 = value1,
.Property2 = value2
}
用于添加一系列新元素
list += From x As T
In source
Where True = <test>
Select New <Type> With {
.Property1 = <expression>,
.Property2 = <expression>
}
如果想从列表中删除特定元素
list -= x
或批量删除元素
list -= From x As T
In source
Where True = <test>
Select x
以下是列表 + 运算符的一些示例
' This add operation makes the code more easily to read and understand:
' This function returns a list of RfamHit element and it also merge a
' list of uncertainly elements into the result list at the same time
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
使用 + 运算符将新对象添加到列表中,这种语法可以使代码更具可读性,而不是使用方法 List(of T).Add 造成的差可读性代码
genomes += New GenomeBrief With {
.Name = title,
.Size = last.Size,
.Y = h1
}
' Using the + operator to instead of this poorly readable function code
genomes.Add(New GenomeBrief With {
.Name = title,
.Size = last.Size,
.Y = h1
})
VisualBasic 标识符名称
1. 目录类型
如果可能,所有目录路径变量都可以是 大写,例如
Dim DIR As String = "/home/xieguigang/Downloads"
Dim EXPORT As String = "/usr/lib/GCModeller/"
2. 模块变量
- 如果变量是 私有 的,所有模块变量都应采用 _lowerUpper 格式
- 但如果变量是 Public 或 Friend 可见的,则应采用 UpperUpper 格式
这是一个示例
' Private
Dim _fileName As String
Dim _inDIR As Directory
' Public
Public ReadOnly Property FileName As String
Public ReadOnly Property InDIR As Directory
3. 局部变量和函数参数
如果可能,函数或子程序中的所有局部变量以及函数参数都应采用 lowerUpper 格式
4. 函数和类型名称
对于 Public 成员函数,函数名建议采用 UpperUpper 格式,但如果函数是 Private、Friend 或 Protected 可见的,则建议您的函数以两个下划线开头,例如 __lowerUpper。Class、Structure 名称的定义与函数名相同。
以下是一些函数名示例(示例选自此处)
' Private
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
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()
- 接口类型名称应以大写字母 I 开头,例如 IEnumerable、IList 等
- 枚举类型名称应以小写字母 s 结尾,例如 MethodTypes、FormatStyles
最后,为了提高代码可读性,请尝试 尽可能缩短标识符名称
字符串操作
1. String.Format
对于格式化字符串输出,建议使用 String.Format 函数或 VisualBasic 语言中的字符串插值语法。并且通过使用 String.Format 函数,建议将格式控制字符串放入常量变量中,而不是直接在格式函数中使用
Const OutMsg As String = "Hello world, {0}, Right?"
' blablabla.......
Dim msg As String = String.Format(OutMsg, name)
2. 字符串连接
为了连接大量字符串标记,建议使用 StringBuilder 来完成此任务,不建议直接使用 & 运算符 连接大量字符串集合,原因在于性能问题。
' Convert the input string to a byte array and compute the hash.
Dim data As Byte() = md5Hash.ComputeHash(input)
' Create a new Stringbuilder to collect the bytes
' and create a string.
Dim sBuilder As New StringBuilder()
' Loop through each byte of the hashed data
' and format each one as a hexadecimal string.
For i As Integer = 0 To data.Length - 1
sBuilder.Append(data(i).ToString("x2"))
Next i
Return sBuilder.ToString() ' Return the hexadecimal string.
如果您只是想连接字符串,建议使用共享方法 String.Join。如果字符串标记将由特定分隔符连接,则使用 String.Join 而不是 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)
或者直接使用 String.Join,这种方法比 StringBuilder.Append 更简洁易读
Dim tokens As String()
Dim out As String = String.Join(" ", tokens)
3. 字符串插值
VisualBasic 语言中的字符串插值语法建议用于 构建 SQL 语句和 CLI 参数,因为这种语法非常易于理解和代码可读
Dim SQL As String = $"SELECT * FROM table WHERE id='{id}' AND ppi>{ppi}"
Dim CLI As String = $"/start /port {port} /home {PathMapper.UserHOME}"
所以,使用这种语法特性会使您的代码非常容易阅读和理解代码含义,对吗?
Linq 表达式
如果表达式的输出类型是已知类型,建议所有 Linq 表达式都使用 LinqAPI 执行
附录
以下是我在编程中使用的一些名称表,并将持续更新....
1. 常用类型的一些常用名称
System.Type | 推荐名称 | 示例 |
System.Text.StringBuilder | sb |
|
System.String | s, str, name, sId, id, x |
|
System.Integer, System.Long | i, j, n, x |
|
System.Object | x, o, obj, value |
|
2. 一些有意义的名称
含义 | 推荐名称 | 示例 |
命令行参数 | args, CLI |
Dim args As CommandLine
Dim CLI As String
Dim args As String()
|
SQL 查询 | SQL, sql, query |
Dim SQL As String = "SELECT * FROM table LIMIT 1;"
|
迭代器 | 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
' blablabla...
Loop
|
Linq 查询表达式 | 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)
|
查询结果/函数返回值 | 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
|