Visual Basic .NET(VB.NET)是.NET框架和后来的.NET下的一种多重编程范式高级语言。
编程范型 | 多重编程范式(结构化,指令式,面向对象及宣告式) |
---|---|
设计者 | 微软 |
实现者 | 微软 |
发行时间 | 2001年 |
当前版本 | |
类型系统 | 静态、强类型、同时为类型安全和不安全[4],标明类型系统 |
操作系统 | 主要在Microsoft Windows 同时可支持Android、BSD、iOS、Linux、Mac OS X、Solaris和Unix |
许可证 | 专有软件(商业软件/免费软件) |
文件扩展名 | .vb |
网站 | msdn |
主要实现产品 | |
Microsoft Visual Studio、Microsoft Visual Studio Express、.NET Framework SDK及Mono | |
派生副语言 | |
Small Basic | |
启发语言 | |
Visual Basic,C# |
VB.NET,是微软公司于2002年作为原有的Visual Basic的继承者而推出。虽然自2005年起,语言名称中的“.NET”就已经被去掉了。但为了与VB 6.0及以前版本的Visual Basic进行区分,“Visual Basic .NET”的名字仍然被社会公众用来指代VB 7.0及以后的Visual Basic。VB.NET与C#同为.Net Framework框架下两种主要的程式设计语言,都是为了调用.Net Framework的类库资源,因此两种语言具有很高的对应性,数据类型、控制结构与语言特性都存在一一对应,容易把原始码从一种语言对译为另一种语言。
微软公司的集成开发环境Visual Studio是最为广泛使用的VB.NET开发工具。然而Visual Studio的大部分版本都是价格不菲的商业软件,除了Express版本和Visual Studio Community(以上两者皆为免费软件)。除了Visual Studio,SharpDevelop和Mono也是可用的VB.NET开发环境。
数据类型与字面常量表示
VB.Net的数据类型,实际上是.Net Framework定义的数据类型。
类型名 | 字节长度 | 取值范围 | 表示法 |
---|---|---|---|
Short | 2字节 | -32768~32767 | number S |
Integer | 4字节 | -2 147 48 3 648~2 147 483 647 | number I |
Long | 8字节 | -9223372036854775808 ~ 9223372036854775807 | number& numberL |
Single | 4字节 | 7位有效数字 | num! numberF |
Double | 8字节 | 15/16位有效数字 | id# numberR |
Decimal | 16字节 | 29位有效数字 | id@ numberD |
Currency | 8字节 | 小数点右4位,左15位 | number@ |
Byte | 1字节 | 0-255 | |
Char | 2字节 | UTF-16字符 | "d"C |
DateTime | 8字节 | 0001-01-01T00:00:00.000 ~ 9999-12-31T23.59.59.999 | #4/102008 06:01:23.456 PM# |
Boolean | 2字节 | True(-1) False(0) | |
String | UBSTR, 字符数量*2+2 | UTF-16字符串 | "Hello"$ |
Object | 4字节 | ||
Variant |
此外,还有SByte、UShort、UInteger、ULong等无符号数据类型。
&O123表示八进制;&H123表示十六进制。
语法特性
VB使用的名字是大小写不敏感的。但是,CLR是大小写敏感的。所以建议保持一致的大小写。
VB自版本5以后的数据类型来源于COM,而其根源是OLE数据类型。
- Nothing(C#的null)表示Object类型的变量(即COM中的IDispatch指针,VB中的所有类和控件均由IDispatch派生)为空。对于引用型变量,表示未绑定到一个物理实体对象。
- Empty表示VARIANT类型变量未初始化(即COM中的VARIANT结构体中的VT成员值为VT_EMPTY)。
- Null表示VARIANT类型变量已初始化,其值为Null,这时COM中的VARIANT结构体中的VT成员值为VT_NULL。通常是所要表示的值不存在或者有问题不合规。实际上,一个引用型变量如果被赋值为Null,则它绑定的地址为0x0000
- 零长度字符串(空字符串)需要分配内存,只不过内存(即COM中的BSTR字符串)头4个字节记录的长度为0。VB.Net定义了一个Public Shared Readonly Empty As String = ""。对于仅声明但未实例化的String对象,实际上都绑定到String.Empty对象上。
- vbNullString没有分配数据内存,实际上定义为Dim *vbNullString As String = Nothing。但又规定了字符串比较时vbNullString = ""为真。
在与空值做比较时,需要区分各种不同用法:
- 对象(引用型变量)是否为Nothing,可用IsNothing(对象名),对象名Is Nothing,对象名IsNot Nothing等
- 在比较数据库的一个字段的值是否为空,在.Net中应该用IsDBNull函数或Convert.IsDBNull方法。例如IsDBNull(recordSet("Column1").Value))或者recordSet("Column1").Value=DBNull.Value。因为DBNull是派生自Object的一个类,DBNull.Value是它的唯一的值。而数据库中的字段值,在DataRow中总是表示为Object,永远不可能为nothing。
- 比较字符串对象是否为空串,实际上规定了下述三种是等效的:
- 对象名 = ""
- 对象名 = String.Empty
- 对象名 = vbNullString
对于可空类型,实际上是Nullable(Of T)泛型结构。例如,下述三行等价:
Dim ridesBusToWork1? As Boolean Dim ridesBusToWork2 As Boolean? Dim ridesBusToWork3 As Nullable(Of Boolean)
比较表达式someVar = Nothing的结果永远是Nothing,应该用someVar.HasValue()方法去判断是否为空,或者用Is或IsNot关键字。
Dim arr([upperLimit]) As dataType = new dataType([upperLimit]) {[initialValues]} '声明数组
arr(index) = value '使用数组
数组的下标开始自0,这遵从了.NET的标准。如果不指定数组的下标上界,则为动态数组,其长度可以动态调整。
- If语句
If 条件 Then
语句
ElseIf 条件 Then
语句
Else
语句
End If
- Switch语句
Select Case Variable
Case Value1
Statements
Case Value2
Statements
Case Value3
Statements
...
Case Else
Statements
End Select
包括下述几种:
- For...Next循环
For varName = 初值 To 终值 [Step 步长]
循环体语句
Next varName
- Do循环
Do [{While|Until} condition]
statements
[Exit Do]
Loop
或
Do
statements
[Exit Do]
statements
Loop [{While|Until} condition]
- While循环
While condition
statements
[Exit While]
statemenst
End While
- For Each...Next循环
For Each element in group
statements
Next [element]
实现迭代器遍历一个序列,每次获取一个返回值。迭代器可以作为一个方法或属性的get访问器,其中的Yield 语句返回迭代器的返回值,并记住当前执行的位置。下次再调用迭代器,从该执行位置恢复执行,直至迭代器代码执行完或者遇到Exit Function或Return语句。编译器把迭代器作为一个状态机的类。
Sub Main()
Dim days As New DaysOfTheWeek()
For Each day As String In days
Console.Write(day & " ")
Next
' Output: Sun Mon Tue Wed Thu Fri Sat
Console.ReadKey()
End Sub
Private Class DaysOfTheWeek
Implements IEnumerable
Public days =
New String() {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
Public Iterator Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
' Yield each day of the week.
For i As Integer = 0 To days.Length - 1
Yield days(i)
Next
End Function
End Class
面向对象时,类的声明示例:
Public Class className [Inherits bassClassName]
Public varName As Integer '資料成員
Public [ReadOnly/WriteOnly] Property propertyName() As Integer '屬性
Public Get
Return m_var
End Get
Public Set(ByVal value As Integer)
m_var=value
End Set
End Property
Public Sub subName(ByVal param1 As Integer) '方法
End Sub
Public Function funcName(ByVal param2 As Integer ) As Integer '函數
Return 101
End Function
[atrributive_list][accessibiliby][Shadows]Event eventName([Parameter]) [Implements interfaces.event] '事件
Public Sub new([Parameter]) '類的構造子(constructor),可以有多個(即可以重載)
End Sub
End Class
上述示例中的Public关键字表示可存取性(accessibility),表示可以被任意代码存取;它可以替换为其他的可存取性:Private(仅限该Class自身存取)、Friend(仅限同一项目中的代码存取)、Protected(仅限自身或派生类存取)、Protected Friend等。如果使用ReadOnly,则表示资料成员或属性是只读;WriteOnly表示只写。Shadows关键字表示覆盖父类中同名(但不一定参数相同)的Event。使用关键字MyBase引用基类。
类可用继承修饰符:NotInheritable关键字,表示该类不能做基类;MustInherit关键字,表示这是一个抽象类。
类的属性与方法能否被覆盖:Overridable关键字表示可被覆盖;Overrides关键字表示覆盖了基类中同名的方法或属性;NotOverridable关键字表示不可覆盖;MustOverride表示方法或属性仅声明没有实现,这时该类必须有MustInherit修饰符,是一个抽象类或者接口,仅能包含属性、方法、函数的声明。
如同其他.Net语,Visual Basic不允许多重继承,但可以同时实现多个interface。
接口是一类特殊的抽象类,不能包括可执行代码与类的资料成员的声明:
Interface interfaceName
Event eventName([param])
Property [ReadOnly/WriteOnly] propertyName As typeName
Function funcName([param]) As returnTypeName
End Interface
接口中这些成员都强制是Public可存取性。
实现一个接口,使用Implements关键字:
Public Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
基于继承的多态,是指用基类类型的变量绑定不同的子类物件,这样调用基类变量的方法,在执行时动态确定实际执行了哪个派生类的同名的方法。多态的优点是可以针对基类(或接口)的方法来写一个通用的过程或者资料容器,适用于各种不同的派生类的具体实现。
委托本质上是一种Class,派生自System.Delegate,包含了三部分资料:一个类物件的地址、该物件所属类的一个方法的地址,以及另一个委托的引用(reference)。前两部分可以实现对一个类物件的方法的调用;第三部分把委托形成一个链接串列,使其依次被调用执行。如下声明了一个委托:
Delegate Sub PlayHandler(ByVal sender As Object, ByVal e As System.EventArgs)
委托常用于事件处理(Event Handler)。.Net Framework的事件是类的属性(实际上是一个嵌套类),用于封装参数格式固定的委托;该委托的参数总是为(ByVal sender As Object, ByVal e as System.EventArgs),返回值为void(即Sub类型)。例如:
Public Class clsName Public Event monitor As PlayHandler End Class
对一个具体的实例,可以给它的事件在运行时动态追加上一个或多个事件处理函数:
AddHandlerins.monitor, AddressOf playHandle_1
AddHandle指向引发事件的对象;AddressOf把一个函数或过程名转化为一个隐式创建的委托实例,用于确定该事件物件所要调用的事件进程。在AddressOf关键字可隐式创建一个引用特定过程的委托的实例。
程序可以抛出一个事件:
Dim WithEvents e As New System.EventArgs Dim ins As New clsName RaiseEvent ins.monitor(ins,e)
using语句,定义一个范围,在范围结束时自动释放对象所占用的资源。
Using conn As New SqlConnection'当在某个代码段中使用了类的实例,而希望无论因为什么原因,只要离开了这个代码段就自动调用这个类实例的Dispose。 '执行代码 End Using
例如:
Public Property pa As String=""
集合(Collection)对象的初始化与普通类对象的属性初始化,分别使用From与With关键字。例如:
Public Class Person
Public Property age As Integer
Public Property Name As String
End Class
Dim personList As New List(Of Person) From {
New Person With {.Name = "Qiang", .age = 24},
New Person With {.Name = "Wei", .age = 42}
}
例如:
Dim people = New With {.name="kyo", .age=22}
即无名的函数或过程,作为表达式的值。可以写为一行或多行。例如:
Dim func1=Function(i As integer) i+10 Dim action = sub() End Sub Dim func2 = Function() End Function
可以在声明匿名函数的同时调用它。单行的lambda表达式不能使用Return关键字,其返回类型是自动推导得出;其参数要么都是用As关键字指明类型,要么全部是自动推导出类型。
lambda表达式在定义时可以使用所在上下文(context,即C++语言的闭包closure)的局部变量、参数、属性、Me等等的值,即使lambda表达式离开了定义时所在的context,这些被使用的局部变量等的值仍然有效。这是因为lambda表达式在定义时把所用到的context的值保存到它自己的定义类中。lambda表达式可以嵌套定义。
例如:
Imports System.Runtime.CompilerServices <Extension()> Public Function funcName(ByVal ins As className) As String 'Do something End Function
Try
' write the condition here
Catch ex As Exception When condition
' Handle Exception when a specific condition is true
Catch ex As Exception
' Handle Exception
Finally
' Cleanup, close connections etc
' NB this code is always executed regardless of if an Exception was raised or not!
End Try
From element [ As type ] In collection [, element2 [ As type2 ] In collection2 [, ... ] ] [Where 表达式]
这里给出了一个Hello World的例子。通过它们您可以更好地理解Visual Basic的特性。(此原始码运行于命令行下)
Module Mdl_Main
Sub Main()
Console.WriteLine("Hello World")
End Sub
End Module
这个程序能输出Hello World。
Module Mdl_Main
第一行是模块定义,命名空间的定义一般可以省略。VB.NET中,所有函数,过程与变量的声明都必须在模块或者类的内部,而不能直接存在于命名空间内部。
Sub Main()
第二行定义了名为Main的过程。一般来说,“Sub Main()”是程序的入口点。
Console.WriteLine("Hello World")
第三行输出“Hello World”。
End Sub
第四行结束了过程Main的定义。
End Module
第五行结束了模块Mdl_Main的定义。
与旧版VB(VB 6.0及以前)相比较,VB.NET明显受到了.Net Framework中其他语言思想的影响。与旧版VB相比,VB.NET更加严格而不失灵活。
Long
类型与Integer
类型的长度分别倍增,达到了64位和32位。- 事件的处理过程不再依赖于名称,而是通过
Handle
子句进行静态绑定或者在运行时进行动态绑定。例如处理按钮控件Button1
的Click
事件:
Visual Basic 6:(注意此过程的名称不可改变)
Private Sub Button1_Click()
'Work to do
End Sub
VB.NET:(注意此过程的名称无关紧要)
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
'Work to do
End Sub
与C家族语言相比,VB.NET则较多保留了VB的特征,比如:
- 与C家族语言统一使用
{
、}
定义语句块不同,VB.NET每种语句块都有对应的开头与结尾。如If ... Else ... End If
,Class ... End Class
。 - VB.NET定义变量使用
Dim
关键字,同时使用Public
、Private
或Protected
表明作用域时可以省略Dim
。 - VB.NET表示变量类型的方式是在变量名后附加
As Type
(Type为变量类型),而C家族语言是在变量名之前书写类型名,无论在定义变量时还是在函数与形参的声明时都是这样。 - VB.NET中有没有返回值的特殊子过程
Sub
。VB.NET中没有void
类型,C#中返回值为void
的函数对应了VB.NET中的Sub
。 - VB.NET中有一种特殊的类型
Module
,相当于C#中的static class
。
下面这两份功能一致的代码展现出了VB.NET与C#的很多不同之处:
- VB.NET:
Namespace N
'Comment
Module M
Public Function GetSum(arr() As Integer) As Integer
Dim Sum = 0 'Auto Type Infer
Dim i As Integer
For Each i In arr
Sum += i
Next
Return Sum
End Function
End Module
Class C
Private v As Integer
Public Function F() As Integer
Return v * v
End Function
Public Sub S(value As Integer)
Me.v = value
End Sub
Public Sub New() 'Constructor
Me.v = 0
End Sub
End Class
End Namespace
- C#:
namespace N
{
//Comment
static class M
{
int GetSum(int[] arr)
{
var Sum = 0;
int i;
foreach(i in arr)
{
Sum += i;
}
return Sum;
}
};
class C
{
private:
int v;
public:
int F()
{
return v * v;
}
void S(int value)
{
this.v = value;
}
C() //Constructor
{
this.v = 0;
}
};
}
VB.NET与C#同为.Net Framework的两大主力程式设计语言,尽管有着各种各样的不同,两者最终都编译为MSIL并由CLR运行。两者功能基本一致,并可以在.Net Framework框架下方便地互相调用与协同开发。关于两者的优劣一直见仁见智。
C语言编写的DLL文件,VB在调用时,需要注意:对于C语言的数组指针,在VB中调用时应将数组的首元素传递给DLL。不能直接传递数组名,因为如果传递数组名,VB实际会传一个复杂的结构类型给DLL。C函数无法确定数组大小,通常用另一个参数指出数组的大小。
<DllImport("D:\GenericMESDLL.dll", CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Cdecl)>
Public Sub test(ByVal param As Integer, ByRef OK As Integer)
End Sub
'下述方法只能使用_stdcall调用约定:
Public Declare Function test1 Lib "D:\PackingDLL.dll" Alias "_test@4" (ByVal param As Integer) As Integer
历史
Visual Basic .NET(VB 7.0)是随Visual C#和ASP.NET一起在2002年发布的最初始的VB.NET版本。C#被大力宣传为微软对付JAVA的王牌,受到媒体极力关注。然而VB.NET(有时被称为VB 7.0)影响面不广,这导致VB社区之外很少人关注它。那些试用过此版VB.NET的人在层层幕布下发现一个强大却艰深的语言,而且还有不少缺点,例如它的运行阶段组件(Run-Time)比VB6大了十倍,存储器使用量也大大增加。
VB 7.0引起了广泛的争议,主要原因在于对旧版VB的改动过大。许多资深的VB程序员抱怨VB.NET,因为VB.NET 2002丢掉了许多不再发行的VB6中使用的大量语言结构和用户界面功能,并且对保留下来的东西也改变了语意。例如,在VB.NET参数默认是以值方式传递的,而不是以引用方式。VB.NET 2002被半嘲讽半认真地称为Visual Fred或VB DOTNOT。作为对2005年3月8日微软拒绝为VB6再提供维护与支持的回应,当月月底出现了反对者的请愿[6]。
VB.NET的支持者们认为新语言在很多方面比旧版本更为强大,比如它以相比早期版本更为自然、紧密和完全的方式地加入了现代面向对象的编程范式。反对者们有不同意见,虽然VB6对对象模型支持有缺点,但是二次开发升级到VB.NET的成本比升级后的收益要高得多。而开发软件发布因特网版本的独立程序员也对VB.NET的RunTime尺寸过大不满。
针对开发者的不满,微软主要做了如下努力:使新的开发更容易启动,而把已经开发的VB6代码升级到VB.NET[7]。例子主要包括:完成VB6中的常见任务如打印预览;集成VB6和VB.NET解决方案(dubbed VB Fusion),从VB6代码转换到VB.NET。
微软在后续版本中撤销了一些过激的更改,并且吸取了经验。在以后版本中,语法的更改变得更加谨慎。
Visual Basic .NET 2003(VB 7.0)和.NET Framework 1.1一起发布。新功能包括对.NET Compact Framework的支持和更好的VB升迁向导。并改进了运行状况,IDE稳定性(尤其是后台编译器),以及运行时RunTime稳定性。另外,VB.NET 2003还有一个学院版Visual Studio .NET 2003 Academic Edition(VS03AE),它是分发给各国某些学者免费使用的版本。
Visual Basic 2005(VB 8.0)是VB.Net的重大转变,微软决意在其软件名称中去掉了.NET部分。在VB2005中,微软增加了许多新功能,以引用VB对于初学者来说的一些优点:
主要的变动:
- 不再支持“Edit and Continue” - 早期Visual Basic可以在调试时修改代码并且不经重新编译地执行。Visual Basic 2005去掉了这个功能;
- 设计时表达式求值;
- 提供My伪命名空间,包含了不需大量编码而访问特定.NET Framework功能的简单方式;提供了改进的VB到VB.NET转换向导;Using语法,简化了需要部署pattern to free resources的对象的使用;My编码,可隐藏由VB.NET IDE写的模板代码;数据源绑定,简化了数据库C/S开发。上述功能(尤其是My)增强了VB.Net成为快速开发应用平台的可能,并与C#进一步区别开来。Visual Basic 2005通过增加新功能而减小了和其它所谓更强大的.NET语言的差距。
- 增加了.NET 2.0语言功能包括:泛型(generics)和Partial类(在一个文件里定义一个类的某部分然后在另外的文件里添加更多的定义,这个方法在集成用户书写的代码和系统自动生成的代码时尤其有用);
- XML注释,可以被NDoc等工具处理而自动生成文档;
- 操作符重载;
- 支持在其它语言中已经广泛使用的unsigned integer数据类型;
- 支持在许多C派生编程语言已提供的复合操作符如:"+=", "-=";
- IsNot专利:If Not X Is Y表达式被转换成If X IsNot Y。当微软为IsNot申请专利时招致了恶名(尤其来自Real公司);
- Visual Basic 2005 Express:作为VS产品线上的一部分,VB2005 Express是专为业余爱好者和新手定制的免费的VS Express系列的一员。Express版本目的定位在帮助人们学习一种语言,所以他们有和标准版一致的用户界面,只是少了一些高级功能。另外,VS Express版包括了VB6.0转换器,提供了从VB老版本升级的可行方法。
Visual Basic 2008(VB 9.0)于2007年11月9日与Microsoft .NET Framework 3.5一起发布。
在VB2008中,微软增加了许多功能,包括:
- IIF函数
- 匿名类型
- 支持LINQ
- Lambda表达式
- XML数据结构
- 类接口
Visual Basic 2010于2010年4月发布。
Visual Basic 2015(VB 14.0)于2015年7月20日发布。
[8] 2022 年 9 月 13 日 - Visual Studio 2022 17.0.14版 NewReleaseIcon
2022 年 8 月 9 日 - Visual Studio 2022 17.0.13版
2022 年 7 月 12 日 - Visual Studio 2022 17.0.12 版
2022 年 6 月 14 日 - Visual Studio 2022 17.0.11版
2022 年 5 月 10 日 - Visual Studio 2022 17.0.10 版
2022 年 4 月 19 日 - Visual Studio 2022 17.0.9版
2022 年 4 月 12 日 - Visual Studio 2022 17.0.8版
2022 年 3 月 8 日 - Visual Studio 2022 17.0.7 版
2022 年 2 月 8 日 - Visual Studio 2022 17.0.6版
2022 年 1 月 13 日 - Visual Studio 2022 17.0.5 版
2021 年12 月 16 日 - Visual Studio 2022 17.0.4版
2021 年 12 月 14 日 - Visual Studio 2022 17.0.3 版
2021 年 11 月 30 日 - Visual Studio 2022 17.0.2版
2021 年 11 月 16 日 - Visual Studio 2022 17.0.1版
2021 年 11 月 8 日 - Visual Studio 2022 17.0.0 版
参考资料
参见
外部链接
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.