前排提醒:阅读此文章并充分尝试 ModVB 的新语法需要较长的时间。对于程序员而言,如果你工作时不用 VB,则最好避免在上班时间看,以免被领导认为你在长时间摸鱼。
ModVB 是一个免费和独立的 VB.NET “mod”,装一个 VSIX 和对应的 NuGet 包就能用新功能。
其中 mod 的意思包含:修改版(modified),现代(modern),以及 取模运算(modulo) (VB + ModVB) Mod VB = ModVB。
Anthony D. Green 在微软的托管编程语言团队有八年工作经验。大多时候是 Roslyn 编译器团队的项目群 / 项目集经理(Program Manager)。他从 13 岁起从 VB4 开始编程,在发布 ModVB 的第一个公测版本时 37 岁。
注:编写此文章时,Visual Studio 2022 版本为 17.3.2,插件版本为 0.0.1.0。示例中使用的操作系统是 Windows 10 x64 专业版 21H2,简体中文。
此步骤用于隔离装了 ModVB 的环境和没装的环境,以便插件的分别管理。
devenv /rootSuffix ModVB"C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe" /rootSuffix ModVB
从菜单上打开 工具→选项,左侧找到 环境→扩展
添加其他扩展库:
https://www.myget.org/F/modvb/vsix/点击应用(Apply)

还是在选项对话框里。左侧找到NuGet包管理器→程序包源
在右边添加新的包源并且确保它已经打勾
https://www.myget.org/F/modvb/api/v3/index.json点更新,然后确定。


注:由于代码高亮不完全支持这种修改过的 VB,对于未提及运行结果的代码,使用截图表示。仅对于代码高亮没问题的代码和带有执行结果的代码使用文本表示。

如果下载速度慢,请自备对MyGet有效的加速器,或者找已经下载了并且你相信的人分享。
使用 JSON 相关语法之前首先需要选择 JSON 常量使用哪些库。目前可选的有 Newtonsoft.Json 和 System.Text.Json。
如果选择 Newtonsoft.Json,则需要安装

如果选择 System.Text.Json,则需要安装

默认情况下,JSON 常量和模式匹配使用 Newtonsoft.Json 定义的类型。如果选择它之外的库,则需要定义编译常量来更改默认类型。
假设有个项目,上述两种库都安装了。默认情况下,Json 对象是 Newtonsoft.Json.Linq.JObject。

如果想要默认用 System.Text.Json,需要在项目文件中定义编译常量。
<PropertyGroup>
<DefineConstants>DEFAULT_JSON_OBJECT_TYPE = "System.Text.Json.Nodes.JsonObject",DEFAULT_JSON_ARRAY_TYPE = "System.Text.Json.Nodes.JsonArray"</DefineConstants>
</PropertyGroup>
效果如下图所示

那么,如果一个项目里想同时使用两种JSON类型呢?也是能做到的。只不过你需要写上JSON变量的类型,而不是让编译器自动推断类型。

就像变量可以用 XML 常量初始化一样,ModVB 支持用 JSON 常量初始化变量,并且用法与 XML 常量有一定的相似性。
此章节的示例使用 Newtonsoft.Json 作为默认 JSON 类型。
以 NuGet 工具版本查询结果的片段为例。请求 https://dist.nuget.org/tools.json 能够得到类似于这样的 JSON并存储在变量中:

假如你打算生成类似的 JSON,可以把别的变量直接写进去换掉JSON的值。

有更多的版本需要显示也是没问题的,可以用 LINQ 表达式做个 JSON 对象数组出来,然后放到总的 JSON 里面。具体做法可参照下面的示例。
下列代码展示如何用 LINQ 结合 JSON 常量语法拼一个新的 JSON 出来。
ModVB
Module Program
Sub Main()
Dim latestVersion = "6.3.0"
Dim stableVersions = {
(ver:="6.2.1", uploaded:="2022-06-14T17:00:00.0000000Z"),
(ver:="6.2.0", uploaded:="2022-05-10T13:00:00.0000000Z"),
(ver:="6.1.0", uploaded:="2022-02-15T13:00:00.0000000Z")
}
Dim nugetVersions = {
"nuget.exe": [
{
"version": latestVersion,
"url": $"https://dist.nuget.org/win-x86-commandline/v{latestVersion}/nuget.exe",
"stage": "Released",
"uploaded": "2022-08-09T13:00:00.0000000Z"
},
From verInfo In stableVersions
Select {
"version": verInfo.ver,
"url": $"https://dist.nuget.org/win-x86-commandline/v{verInfo.ver}/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": verInfo.uploaded
}
]
}
Console.WriteLine(nugetVersions)
End Sub
End Module
这段代码的运行结果是:
JSON
{
"nuget.exe": [
{
"version": "6.3.0",
"url": "https://dist.nuget.org/win-x86-commandline/v6.3.0/nuget.exe",
"stage": "Released",
"uploaded": "2022-08-09T13:00:00.0000000Z"
},
{
"version": "6.2.1",
"url": "https://dist.nuget.org/win-x86-commandline/v6.2.1/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": "2022-06-14T17:00:00.0000000Z"
},
{
"version": "6.2.0",
"url": "https://dist.nuget.org/win-x86-commandline/v6.2.0/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": "2022-05-10T13:00:00.0000000Z"
},
{
"version": "6.1.0",
"url": "https://dist.nuget.org/win-x86-commandline/v6.1.0/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": "2022-02-15T13:00:00.0000000Z"
}
]
}
上面的例子如果你觉得 nugetVersions 的变量声明太长了,你可以提取变量出来。JSON 常量支持扁平化操作,能够用来将多个 JSON 对象合并成一个,而不导致对象层次加深。
下面的代码将第一个版本信息中的两个属性提取了变量出来,并且剩余版本信息提取出了另一个变量。程序的执行结果不变。
ModVB
Module Program
Sub Main()
Dim latestVersion = "6.3.0"
Dim stableVersions = {
(ver:="6.2.1", uploaded:="2022-06-14T17:00:00.0000000Z"),
(ver:="6.2.0", uploaded:="2022-05-10T13:00:00.0000000Z"),
(ver:="6.1.0", uploaded:="2022-02-15T13:00:00.0000000Z")
}
Dim stable = From verInfo In stableVersions
Select {
"version": verInfo.ver,
"url": $"https://dist.nuget.org/win-x86-commandline/v{verInfo.ver}/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": verInfo.uploaded
}
Dim releasedStage = {
"stage": "Released",
"uploaded": "2022-08-09T13:00:00.0000000Z"
}
Dim nugetVersions = {
"nuget.exe": [
{
"version": latestVersion,
"url": $"https://dist.nuget.org/win-x86-commandline/v{latestVersion}/nuget.exe",
{releasedStage}
},
stable
]
}
Console.WriteLine(nugetVersions)
End Sub
End Module
JSON模式匹配能在判断JSON的结构和内容的同时将所需的信息提取成变量。
以 JSON 常量例子中的 JSON 为例。假设你需要取得所有 stage 是 ReleasedAndBlessed 的 nuget.exe 版本以及其它信息,可以用下面的代码:
ModVB
Console.WriteLine("所有已发布的稳定版:")
Select Case ShapeOf nugetVersions
Case {"nuget.exe": nodes}
For Each node In nodes
Select Case ShapeOf node
Case {
"version": ver As Version,
"url": url As String,
"stage": "ReleasedAndBlessed",
"uploaded": relaseDate As Date
}
Console.WriteLine($"{ver} 发布于 {relaseDate:F},下载地址是 {url}")
End Select
Next
End Select
代码产生以下输出
控制台
所有已发布的稳定版:
6.2.1 发布于 2022年6月15日 1:00:00,下载地址是 https://dist.nuget.org/win-x86-commandline/v6.2.1/nuget.exe
6.2.0 发布于 2022年5月10日 21:00:00,下载地址是 https://dist.nuget.org/win-x86-commandline/v6.2.0/nuget.exe
6.1.0 发布于 2022年2月15日 21:00:00,下载地址是 https://dist.nuget.org/win-x86-commandline/v6.1.0/nuget.exe
Select Case ShapeOf 是模式匹配专用的 Select Case。它会改变Select Case内Case的含义,让它进行模式匹配,而不会与常规的 Select Case 语法产生冲突。
匹配 JSON 对象需要用一对大括号包含 JSON 匹配模式,以下图为例解释。

匹配 JSON 数组需要用一对中括号包含 JSON 匹配模式,以下图为例解释。

"元素1", "元素2", 345, true, false, null 。如果数组比预期的长,匹配仍然能够成功。任何 VB 常量表达式在这里都能使用。包括 Date, Decimal, Nothing。JSON 的常量(true, false, null)也能用。

TryCast, VB 内置的转换规则 以及 TryParse 之类的其它转换方式。TryParse。
基本上每个模式匹配表达式最后都可以写一个问号,让表达式也能匹配空。这里认为属性未定义和值为空是相同的情况。下图是一些例子。



当属性值为空时,定义的变量具备它的默认值。
JSON 常量和模式匹配是基于模式的,类似于 LINQ 和 For Each 循环。它并不会绑在特定的库和类型上。这些功能在分析或编译代码时从特定的命名空间查找符合条件的类型,使用其中的成员。你甚至可以只装包含 ModVB 编译器的包,具体的模式匹配拓展包由你自己编写。通过反编译你的使用 JSON 常量和模式匹配的项目,你可以了解到如何编写 JSON 常量拓展包和模式匹配拓展包。
ModVB 作者写的两篇介绍:
此文章使用 CC BY-SA 4.0 协议,示例代码使用 MIT 协议。
此文章目前计划在 博客园,GitHub,哔哩哔哩,百度贴吧 使用用户名为 Nukepayload2 的账号发布。如果文章在别的地方出现,或者用户名不是 Nukepayload2,则属于被转载。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h