
本章是为曾经使用 Visual Basic 和 C# 编程,并希望完全转向 X# 或在特定项目中使用X# 的读者准备的。这两种情况都有可能发生,而且 X# 可能会让你的开发效率更高一些,因为它的语法可能更容易使用,也更为 Visual Basic 开发人员所熟悉。
关于 X# 最重要的一点是,X# 100% 基于CLR,是 100% 的 .Net 语言。因此,它使用与其他.Net 语言相同的类型系统、相同的日期类型(尽管名称有所不同)、相同的异常处理等。当然,引用任何C# 或 VB 程序集都不成问题,反之亦然。C# 的大部分语言特性也是 X# 的一部分。
重要:本章描述的所有语法元素都基于 X# 的 Core 方言。如果使用其他方言(如VO),它们可能会有所不同。此外,X#编译器提供了丰富的开关,允许更改语法的核心内容,如大小写敏感、在引用实例成员时使用self ,甚至数组的基本索引也可以设置为0 而不是 1。
X# 的语法混合了Visual Basic 和 C# 的语法,这非常有意思。它们的相似之处在于
当然,X# 语法的主要基于Visual Objects(简称VO),而VO事实上源自xBase标准(如果你还不了解 "历史事实",那么在维基百科(https://de.wikipedia.org/wiki/Visual_Objects)上回顾历史总是一件乐事--有趣的是,任何关于 "xBase主题"的文章,德文都比英文详细得多。例如,逻辑数据类型是原始 xBase 数据类型的一部分,因此早在 80 年代中期就已经存在。
X# 拥有许多优秀的语言特性,这些特性使其可以与C# 和 Visual Basic 相媲美,甚至在某些情况下略胜一筹。
在当前版本的 X# 中,每一行如果在编辑器中跨越多行,都必须在行尾加上分号(;)。否则,编译器会产生类似 "END NAMESPACE expected(必须使用 END NAMESPACE 结尾)"的错误信息。
虽然我建议将一个很长的代码行拆分成好几行,但我不会与那些喜欢单行代码的开发人员为此争论不休,即使这意味着必须向右滚动几下(况且,40英寸的超宽显示器也让分号(;)无处存放)。

图 3.1:缺少续行符会导致多种错误
注意:C# 不需要续行符,而在 Visual Basic 中,某些行必须以 _ 字符结束。
最重要的区别已在前面提到。在一些情况下,X#开发人员必须学习和使用 C# 语法。例如调试时即时窗口中的 Lambda 表达式或设置断点条件。但这一点会随着新版本的发布而改变。例如,在 X# 2.13中,已经可以在即时窗口中使用 self 或 : 操作符。而在X# 2.17 中,我们必须做出更多的改进,以便使用即时窗口进行表达式求值以尽可能的接近C#。由于 C# 区分大小写,因此变量名的大小写保持一致仍然很重要。
此外,不要忘记continue 的等价形式是 Loop。否则,你会突然收到一个看起来很有趣的异常。
作为一名长期的VB 开发人员,作者从 1991 年开始使用 Visual Basic 的第一个版本(代号为“thunder”),对我来说,X# 看起来是Visual Basic 的完美继承者。它避免了大小写敏感、大括号和分号等繁文缛节,并且使用了我喜欢的Visual Basic 语法中相同的不言自明的关键字。例如,类中的属性定义可以像在Visual Basic 中一样完成。
当然,这并不意味着X# 与 Visual Basic 完全兼容。例如,My 或 Option Explicit 没有等效项,没有 WithEvents,并且可能还会缺少更多语法元素。
我主要指的是一般的语法。
对我来说,X#,尤其是在与 Visual Studio 一起使用时,在许多方面都比Visual Basic 更好,它包含了 C# 的许多成分,却没有诸如必须用分号结束语句之类的 "限制"。
大多数Visual Basic 开发人员都会喜欢 X# 语法。与 Visual Basic 相反,X#仍在积极开发中,并且在可预见的未来仍将如此。尽管X# 不是来自 Microsoft,并且可能不包含 VB 的所有语言功能,但我建议在未来的项目中尝试使用X# 而不是 Visual Basic。
为了让所有读者对 X#、C# 和Visual Basic 进行真正客观的比较,我将介绍一个小型控制台应用程序,该程序用这三种语言从SQLite 数据库中读取一些数据(具体细节将在第16 章中予以说明)。
有趣的是,X# 版本只有 36 行,C#版本如预期一样有 47 行,而 VB 版本只有41 行。当然,代码行数并不能说明什么,比如在 C# 中,当下面的代码块只包含一条命令时,就可以省略大括号。从 C# 第 9 版开始,甚至可以只使用顶层语句,完全省略带有静态main 方法的类定义。在这种模式下,甚至不需要定义启动函数(Visual Basic 没有这种语言特性)。
那么,X# 与 Visual Basic 相比如何呢?这两种语言有许多共同的语法元素。在VB 中,没有与 var 关键字直接对应的语法,但如果没有将 Option Infer On 设置为 off,Dim语句就很接近了。本节中的 X# 程序是用标准 Core 方言编译的。在VO 方言中,X# 运行时的函数与 VB 运行时的函数非常相似,如Instr()、Len() 或 Val()。其中许多函数在X# 中都有直接的对应。Visual Basic 开发人员如果改用 X#,不仅可以获得熟悉的语法,还可以获得 VB 运行时的一百多个函数,其中大部分都是熟悉的。X# 中没有与 VB 中实用的My 命名空间对应的东西,但在 X# 项目中引用 Microsoft.VisualBasic 程序集完全没有问题,这样 My 也可以在 X# 应用程序中使用。
Example 3.1: (XS_DbQueryXS.prg)
// 使用 X# 和数据加载器进行简单的数据库查询
// 使用 xsc /r:runtimeLibs/SQLite x64/System.Data.SQLite.dll 进行编译
USING System.Data
USING System.Data.Sqlite
USING System.Collections.Generic
INTERNAL CLASS Book
INTERNAL PROPERTY Title AS STRING AUTO
END CLASS
FUNCTION Start() AS VOID
Console.WriteLine("*** 这是 X# ***")
VAR books := List<Book>{}
VAR cnStr := "Data Source=./BookLib.db3"
LOCAL cn := NULL AS SqliteConnection
TRY
cn := SQliteConnection{cnStr}
cn:open()
VAR cmd := cn:CreateCommand()
cmd:CommandText := "Select * From Book"
VAR dr := cmd:ExecuteReader()
WHILE dr:Read()
books:Add(Book{}{Title := dr:GetString(dr:GetOrdinal("Title"))})
END WHILE
CATCH ex AS SystemException
Console.WriteLine(i"Error: {ex:Message}")
FINALLY
IF cn != NULL
cn:Close()
ENDIF
END TRY
FOREACH VAR book IN Books
Console.WriteLine(String.Format("Title: {0}", book:Title))
NEXT
RETURNExample 3.2: (XS_DbQueryCS.cs)
// 使用 C# 和数据加载器进行简单的数据库查询
using System;
using System.Data;
using System.Data.SQLite;
using System.Collections.Generic;
internal class Book
{
internal string Title { get; set; }
}
class Application
{
static void Main()
{
Console.WriteLine("*** 这是 C# ***");
var books = new List<Book>();
var cnStr = "Data Source=./BookLib.db3";
SQLiteConnection cn = null;
try
{
cn = new SQLiteConnection(cnStr);
cn.Open();
var cmd = cn.CreateCommand();
cmd.CommandText = "Select * From Book";
var dr = cmd.ExecuteReader();
while (dr.Read())
{
books.Add(new Book() { Title = dr.GetString(dr.GetOrdinal("Title")) });
}
}
catch (SystemException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
if (cn != null)
cn.Close();
}
foreach (var book in books)
{
Console.WriteLine($"Title: {book.Title}");
}
}
}' 使用 Visual Basic 和数据加载器进行简单的数据库查询
Imports System.Data
Imports System.Data.Sqlite
Imports System.Collections.Generic
Friend Class Book
Friend Property Title As String
End Class
Class Application
Shared Sub Main()
Console.WriteLine("*** 这是 Visual Basic ***")
Dim books As List(Of Book) = new List(Of Book)
Dim cnStr As String = "Data Source=./BookLib.db3"
Dim cn As SqliteConnection = Nothing
Try
cn = new SQliteConnection(cnStr)
cn.open()
Dim cmd = cn.CreateCommand()
cmd.CommandText = "Select * From Book"
Dim dr = cmd.ExecuteReader()
While dr.Read()
books.Add(new Book With {.Title = dr.GetString(dr.GetOrdinal("Title"))})
End While
Catch ex As SystemException
Console.WriteLine("Error: " + ex.Message)
Finally
If cn Is Nothing
cn.Close()
End If
End Try
For Each book in Books
Console.WriteLine(String.Format("Title: {0}", book.Title))
Next
Return
End Sub
End Class