Đang tải dữ liệu...
ParkOur Việt

 Bản tin | Bài viết | Thư viện | Diễn đàn | Giới thiệu | Liên hệ | Tìm kiếm 
Trưng cầu ý kiến
Khi xây dựng ứng dụng trên .NET, bạn thích và hay thường sử dụng ngôn ngữ lập trình nào?
 
Tìm kiếm
Tìm kiếm nâng cao
Thống kê
Số người truy cập: 4.342.930
Số người trực tuyến: 59
Trong đó có 4 thành viên: NGUYEN VAN HUY, phan_hen, Duong Cuong, tran van phong
Trang chủ .NET Việt Nam  >  Bài viết  >  Theo chủ đề  >  Nền tảng .NET/Mono

So sánh syntax c# and vb.net

Internet
Internet or Some Document
   
04:12' PM - Thứ hai, 23/06/2008
Sự khác biệt giữa VB.NET và C# được thể hiện ở ba phần chính: cú pháp, các nguyên lý hướng đối tượng, và môi trường phát triển tích hợp Visual Studio .NET. Sự khác biệt về cú pháp liên quan đến các câu lệnh và các yếu tố ngôn ngữ. Sự khác biệt về hướng đối tượng thì khó thấy hơn, liên quan đến bản hiện thực và tính năng giữa hai ngôn ngữ. Sự khác biệt về môi trường phát triển tích hợp bao gồm những thiết lập biên dịch (là những đặc tính được thiết lập thông qua IDE, có tác dụng khác nhau tùy vào ngôn ngữ). Cũng có sự khác biệt thứ tư liên quan đến các tính năng ngôn ngữ có trong ngôn ngữ này nhưng không có trong ngôn ngữ kia.

1. Sự khác biệt về cú pháp

Sự khác biệt về cú pháp là sự khác biệt thông thường nhất mà chúng ta nghĩ đến khi so sánh hai ngôn ngữ. Sự khác biệt về cú pháp đề cập đến sự khác biệt trong từ khóa và định dạng câu lệnh được sử dụng để thực hiện các tác vụ giống nhau. Ví dụ: trong C#, câu lệnh được kết thúc bằng dấu chấm phẩy; trong VB.NET, câu lệnh được kết thúc bằng dãy ký tự chuyển dòng.

1.1 Phân biệt chữ hoa-thường

Một khác biệt chính giữa hai ngôn ngữ là C# có phân biệt chữ hoa-thường, còn VB.NET thì không. Câu lệnh dưới đây đúng trong VB.NET (tất cả đều viết thường):


Code:
        system.console.writeline("hello world")    
Trong C#, câu lệnh trên sẽ phát sinh lỗi. Cách viết đúng câu lệnh này trong C# như sau:

Code:
        System.Console.WriteLine("hello world");    
Cả C# và VB.NET đều biên dịch thành một ngôn ngữ trung gian (Intermediate Language—IL). Điều đáng nói là IL có phân biệt chữ hoa-thường, nghĩa là VB.NET phải chuyển những dòng lệnh lúc biên dịch sao cho trùng khớp dạng chữ của câu lệnh gốc ở mức IL.
Một hiệu ứng lề của việc không phân biệt chữ hoa-thường là có những lúc trình biên dịch không thể so trùng chính xác dạng chữ với khai báo gốc của một hàm, dẫn đến kết quả không chính xác. Ví dụ:

Code:
        Class Account        
Overloads Function toString(ByVal Format As String) As String
Return "My String with Format"
End Function

Overloads Overrides Function toString() As String
Return "My String"
End Function
End Class

Module App
Sub Main()
Dim acct As Object = New Account()
System.Console.WriteLine(acct.ToString())
End Sub
End Module
Trong ví dụ trên, toString không chép đè phương thức ToString trong lớp cơ sở, và phương thức toString không bao giờ được gọi. Ví dụ này cho thấy sự phức tạp của việc có một ngôn ngữ không phân biệt chữ hoa-thường trong khi tất cả đều phân biệt chữ hoa-thường.

Điều gì sẽ xảy ra nếu bạn thêm hai hàm công khai trong C# với tên giống nhau nhưng khác dạng chữ hoa-thường? VB không thể sử dụng hàm này, và báo rằng nó không thể phân giải hàm. Ví dụ, lớp Banking được viết trong C# có hai phương thức MakeDeposit và makedeposit. Bạn có thể tham chiếu DLL trong VB, và tạo một thể hiện của lớp Banking. Nhưng nếu bạn sử dụng phương thức MakeDeposit hay makedeposit, trình biên dịch sẽ không biết phải sử dụng phương thức nào. Để ngăn chặn điều này, bạn có thể yêu cầu trình biên dịch kiểm tra sự chấp thuận của Common Language Specification (CLS) bằng cách thêm dòng lệnh sau vào file AssemblyInfo.cs của dự án C#:

Code:
        [assembly: System.CLSCompliant(true)]    
Nếu đang sử dụng trình biên dịch C#, bạn chỉ việc thêm dòng lệnh này vào file mã nguồn sau các câu lệnh using. Sau khi thêm dòng lệnh này, trình biên dịch C# sẽ thông báo lỗi nếu hai hàm công khai trong lớp của bạn chỉ khác nhau ở dạng chữ.

1.2 Kết dòng
Câu lệnh C# có thể được tách thành nhiều dòng với CRLF và được kết thúc bằng một dấu chấm phẩy. Câu lệnh VB.NET chỉ có thể được tách bằng một ký tự tiếp dòng và được kết thúc bằng CRLF. Đoạn mã sau minh họa cho việc tách dòng trong C#:

C#.NET

Code:
        // Một dòng mã trong C#.        
string sName = sFirstName +
sLastName;
// Dấu chấm phẩy báo hiệu kết thúc câu lệnh.
Bạn có thể tách dòng tại bất kì vị trí nào. Bạn có thể đặt mỗi từ trên một dòng riêng, thậm chí có thể thêm chú thích ở cuối mỗi đoạn. Ví dụ:

C#.NET

Code:
        string        
sName // biến
= // toán tử
sFirstName // tên
+ // toán tử
sLastName;
// Dấu chấm phẩy báo hiệu kết thúc câu lệnh.
Bạn có thể thực hiện tương tự với các chuỗi trực kiện bằng cách đặt biểu tượng @ trước chuỗi:

C#.NET

Code:
        string        
sName = @"John Jacob Jingle
Hymer Smith";
Tuy nhiên, đoạn mã trên cho kết quả là một chuỗi với ký tự xuống dòng được nhúng vào.
Trong VB, để tách một dòng thành nhiều phần, bạn phải thêm một khoảng trắng và ký tự gạch dưới. Ví dụ:

VB.NET

Code:
        ' Một dòng trong VB.        
Dim sName As String = sFirstName + _
sLastName
Giống như C#, bạn có thể tùy ý tách mỗi từ như ví dụ bên dưới. Tuy nhiên, khác với C#, việc thêm chú thích cuối mỗi đoạn là không hợp lệ.

Code:
        ' Một dòng trong VB.        
Dim _
sName _
As _
String _
= _
sFirstName _
+ _
sLastName
Khác với C#, việc tách các chuỗi trực kiện thành hai dòng là không hợp lệ.

1.3 Chú thích

C# phân biệt giữa chú thích dòng và chú thích khối. Chú thích dòng sử dụng hai dấu vạch xiên “//” như sau:

C#.NET

Code:
        // Đây là một chú thích.        
void MakeDeposit(int Amount)
{
int _Balance; // Số dư tài khoản.
}
Chú ý, trong đoạn mã trên, có một chú thích trước khai báo hàm và một chú thích sau khai báo _Balance. Khi bạn sử dụng hai dấu vạch xiên, tất cả văn bản sau hai dấu vạch này được xem như là một phần của chú thích.
Chú thích khối sử dụng một dấu vạch xiên theo sau là một dấu hoa thị (/*) để bắt đầu khối, và kết thúc khối bằng một dấu hoa thị theo sau là một dấu vạch xiên (*/). Ví dụ:

Code:
        /*         
Hàm: MakeDeposit
Tầm vực: Public
Mô tả: Tăng số dư tài khoản.
Tác giả: Alibaba
*/
public void MakeDeposit(int Amount /*chú thích 1*/,
int AmountAvail /*chú thích 2*/) {}
Chú thích khối cho phép bạn viết một đoạn chú thích mà không cần đặt hai dấu vạch xiên trên mỗi dòng, nhưng nó cũng cho phép bạn chèn một chú thích bên trong một dòng mã. Chú thích khối có thể có các chú thích được nhúng bên trong, ví dụ:

C#.NET

Code:
        /*        
// Đây là chú thích được nhúng vào.
*/
VB.NET chỉ có chú thích dòng. Các chú thích được tạo ra với câu lệnh Rem hay với dấu nháy đơn (cách này thường được sử dụng hơn). Ví dụ:

VB.NET

Code:
        ' Đây là một chú thích.        
Rem Đây là một chú thích khác.
Sub MakeDeposit(ByVal Amount As Integer)
Dim _Balance As Integer ' Số dư tài khoản.
End Sub
Một hạn chế đối với các chú thích trong VB là bạn không thể chèn một chú thích vào chính giữa một dòng lệnh như có thể thực hiện với chú thích khối trong C#.
1.4 Khai báo và sử dụng không gian tên

Một không gian tên là một nhóm các lớp có cùng tiền tố. Ví dụ, nếu không gian tên WidgetsUSA có hai lớp Checking và Savings thì tên đầy đủ của hai lớp này sẽ là WidgetsUSA.Checking và WidgetsUSA.Savings.

Cả VB.NET và C# đều cho phép bạn định nghĩa không gian tên. Dưới đây là các ví dụ:

Code:
        namespace WidgetsUSA        
{
namespace Banking
{
public class Checking {}
public class Savings {}
}
}
Code:
        Namespace WidgetsUSA        
Namespace Banking
Class Checking
End Class
Class Savings
End Class
End Namespace
End Namespace
Tên đầy đủ của các lớp trong ví dụ này là WidgetsUSA.Banking.Checking và WidgetsUSA.Banking.Savings. Việc khai báo không gian tên tạo tên lớp duy nhất cho một nhóm cụ thể. Tuy nhiên, nó trở nên cồng kềnh khi phải gõ tên lớp dài trong khai báo. Do đó, mỗi ngôn ngữ cung cấp một câu lệnh cho phép lược bỏ phần tên không gian tên và sử dụng tên lớp rút gọn trong khai báo. Trong C#, điều này được thực hiện bằng câu lệnh using:

C#.NET
Code:
        using WidgetsUSA.Banking;        
class App
{
static void Main()
{
Checking check = new Checking();
}
}
Tương đương với using trong VB là câu lệnh Imports:

VB.NET

Code:
        Imports WidgetsUSA.Banking        
Class App
Shared Sub Main()
Dim check As Checking = New Checking()
End Sub
End Class
Trong C# và VB.NET, bạn có thể gán một danh hiệu cho một không gian tên. Điều này giúp giải quyết vấn đề nhập nhằng khi nhiều không gian tên có tên lớp giống nhau. Xét hai lớp: MyCompany.SharedCode.DatabaseClasses.Connection và SomeOtherCompany.Modem.Connection. Giả sử một lập trình viên viết mã lệnh sử dụng hay nhập không gian tên cho mỗi lớp như sau:

VB.NET

Code:
        Imports MyCompany.SharedCode.DatabaseClasses        
Imports SomeOtherCompany.Modem

Class App
Shared Sub Main()
Dim cn As Connection
End Sub
End Class
Trình biên dịch thông báo Connection trong các khai báo này là nhập nhằng, nó có thể là của một trong hai không gian tên. Một giải pháp là gán một danh hiệu cho một hoặc cả hai không gian tên như sau:

C#.NET
Code:
        using db=MyCompany.SharedCode.DatabaseClasses;        
using SomeOtherCompany.Modem;

class App
{
static void Main()
{
db.Connection cn;
}
}
VB.NET
Code:
        Imports db=MyCompany.SharedCode.DatabaseClasses        
Imports SomeOtherCompany.Modem

Class App
Shared Sub Main()
Dim cn As db.Connection
End Sub
End Class
Câu lệnh using thứ nhất trong C# và câu lệnh Imports thứ nhất trong VB gán một danh hiệu (db) cho không gian tên MyCompany.SharedCode.DatabaseClasses. Sau đó, bạn có thể sử dụng db trong mã lệnh thay vì tên không gian tên. Điều này giúp đánh máy nhanh hơn và cũng giải quyết vấn đề nhập nhằng. Dĩ nhiên, bạn có thể sử dụng tên đầy đủ của không gian tên bất cứ khi nào bạn tham chiếu lớp để giải quyết vấn đề nhập nhằng.

VB có một sự cải tiến so với C#. Nó cho phép bạn sử dụng Imports không chỉ với không gian tên mà còn với tên lớp. Ví dụ:

VB.NET
Code:
        Imports Microsoft.VisualBasic.ControlChars        

Module App
Sub Main()
Dim s As String = "Hello" + NewLine + "World"
System.Console.WriteLine(s)
End Sub
End Module
Câu lệnh Imports tham chiếu một không gian tên (Microsoft.VisualBasic) và một lớp (ControlChars). Do đó, mã lệnh trong Main có thể sử dụng các hằng trong lớp đó mà không phải sử dụng tên đầy đủ của lớp. Một trong các hằng này là NewLine (biểu diễn ký tự xuống dòng).
1.5 Khai báo biến

Trong C#, kiểu biến luôn đứng trước tên biến. Ví dụ:

C#.NET

Code:
        int x;        
decimal y;
rectangle z;
object obj;
Trong VB, tên biến luôn đứng trước kiểu biến. Khai báo biến trong VB bắt buộc phải có Dim hoặc các từ khóa: Public, Private, Friend, Protected, Protected Friend. Khai báo sử dụng Dim thì mặc định là Private. Mã lệnh trong VB như sau:

VB.NET

Code:
        Dim x As Integer        
Dim y As Decimal
Dim z As Rectangle
Dim obj As Object
Cả hai ngôn ngữ đều cho phép bạn tạo một thể hiện của lớp bằng cách sử dụng từ khóa new. Dưới đây là ví dụ trong C#:

C#.NET

Code:
        class Account {}        

class App
{
static void Main()
{
// Ví dụ 1.
Account acct = new Account();

// Ví dụ 2.
Account acct2;
acct2 = new Account();
}
}
Bạn có thể kết hợp khai báo đối tượng và thể hiện đối tượng trên cùng một dòng, hoặc có thể tách chúng ra.
VB.NET có ba cách sử dụng toán tử new, được minh họa như sau:

VB.NET

Code:
        Class Account        
End Class

Class App
Shared Sub Main()
' Ví dụ 1.
Dim acct As Account = new Account()

' Ví dụ 2.
Dim acct2 As Account
acct2 = new Account()

' Ví dụ 3.
Dim acct3 As New Account
End Sub
End Class
Cả ba ví dụ cùng tạo ra cùng IL. Ví dụ 3 tương tự với ví dụ 1, nó khai báo một biến kiểu Account và tạo một đối tượng kiểu Account. Không giống như các phiên bản trước của VB, ví dụ 3 tạo ngay một thể hiện của đối tượng Account. Trong VB6 và các phiên bản trước, khi sử dụng As New, đối tượng sẽ không được thể hiện hóa cho đến khi bạn sử dụng nó.

1.6 Khởi tạo biến

C# bắt buộc bạn phải khởi tạo các biến cục bộ một cách tường minh. Xét khai báo sau:

C#.NET

Code:
        class Account        
{
int Balance; // trường

public void MakeDeposit()
{
int tempBalance; // biến cục bộ
// Lỗi biên dịch.
Console.WriteLine(tempBalance);
}
}
Lớp Account có trường Balance, phương thức MakeDeposit, và biến cục bộ tempBalance. Trong C#, bạn không phải khởi tạo các trường trước khi sử dụng chúng. Các trường sẽ được khởi tạo tự động là 0 nếu chúng là kiểu số, và là null nếu chúng là kiểu tham chiếu. Tuy nhiên, trình biên dịch C# sẽ thông báo lỗi nếu bạn sử dụng một biến cục bộ trước khi gán giá trị cho nó.
Trong VB.NET không có trường hợp này. VB.NET tự động khởi tạo tất cả các biến cục bộ là 0 hay Nothing (hay tương đương, tùy thuộc vào lớp). Xét mã lệnh VB sau:

VB.NET

Code:
        Class Account        
Dim Balance As Integer

Sub MakeDeposit()
Dim tempBalance As Integer
' Không có lỗi biên dịch.
System.Console.WriteLine(tempBalance)
End Sub
End Class
Trong ví dụ trên, cả Balance và tempBalance đều được khởi tạo là 0.Chỉ khi gặp vực thẳm, chúng ta mới tìm được kho báu của cuộc đời.
1.7 Khai báo thông số hàm

Có ba loại chỉ thị thông số: in (tham trị); in, out (tham chiếu); và out. Khi một đối số được truyền bằng tham trị, những thay đổi trong hàm được gọi không bị phản chiếu ngược trở lại caller; khi một đối số được truyền bằng tham chiếu, chúng bị phản chiếu. Với các thông số tham chiếu, bộ nhớ được định vị bởi caller, nhưng hàm có thể thay đổi giá trị. Với các thông số out, bộ nhớ được định vị và giá trị được thiết lập bởi hàm, caller chỉ nhận được giá trị. Cả C# và VB có thể sử dụng cả ba loại thông số. Tuy nhiên, chúng hoạt động hơi khác giữa hai ngôn ngữ. Xét hai ví dụ trong C# sau:

C#.NET

Code:
        void MakeDeposit(int x, ref int y, out int z)        
{
x = 10; // Các thay đổi không bị phản chiếu đến caller.
y = 10; // Các thay đổi bị phản chiếu đến caller.
z = 10; // Bắt buộc. Các thay đổi bị phản chiếu đến caller.
}

void MakeDeposit(object obj1, ref object obj2, out object obj3)
{
obj1 = new object(); // Các thay đổi không bị phản chiếu đến caller.
obj2 = new object(); // Các thay đổi không bị phản chiếu đến caller,
// nhưng giờ đây caller có một tham chiếu đến một đối tượng khác.
obj3 = new object(); // Bắt buộc. Hàm phải định vị đối tượng.
}
Ví dụ thứ nhất nhận các kiểu giá trị, ví dụ thứ hai nhận các kiểu tham chiếu. Cả hai đều minh họa cách gửi một đối tượng bằng tham chiếu. Đôi khi, lập trình viên hiểu sai rằng: khi truyền một đối tượng bằng tham trị cho một hàm, hàm này không thể thay đổi các trường của đối tượng đó. Xét mã lệnh sau:

C#.NET

Code:
        class person        
{
public int Age;
}

class App
{
static void ChangeAge(person p1)
{
p1.Age=10;
}
}
Trong ví dụ trên, p1 là thông số tham trị. “Tham trị” chỉ áp dụng cho đối tượng mà biến trỏ tới; các trường của đối tượng lúc nào cũng có thể bị thay đổi mà không phụ thuộc vào chỉ thị thông số đã được khai báo. Đối với các đối tượng, việc truyền một đối tượng bằng tham trị chỉ có nghĩa rằng: nếu hàm thiết lập biến-đại-diện-cho-đối-tượng thành một đối tượng khác thì caller vẫn giữ tham chiếu đến đối tượng gốc khi hàm này kết thúc. Nếu một đối tượng được truyền bằng tham chiếu và hàm thiết lập biến-đại-diện-cho-đối-tượng thành một đối tượng mới thì caller sẽ giữ tham chiếu đến đối tượng mới khi hàm này trả về.

Các thông số out thực ra là các thông số tham chiếu được đánh dấu bằng một đặc tính đặc biệt để đơn giản hóa cách các thông số được truyền khi truy xuất từ xa. Khi caller và đối tượng ở các máy khác nhau, càng ít dữ liệu được truyền qua mạng càng tốt. Các thông số được truyền bằng tham trị chỉ cần được truyền theo một chiều từ caller đến đối tượng. Các thông số được truyền bằng tham chiếu cần được truyền từ caller đến đối tượng, và ngược lại. Các thông số out chỉ cần được truyền từ đối tượng đến caller.

VB hỗ trợ cả ba loại truyền thông số. Thông số tham trị được chỉ định bằng cách lược bỏ từ khóa chỉ thị giống như trong C# hoặc bằng cách sử dụng từ khóa ByVal:

VB.NET

Code:
        Sub MakeDeposit(ByVal num1 As Integer)        
End Sub

Sub MakeDeposit(num1 As Integer)
End Sub
Thông số num1 được truyền bằng tham trị trong cả hai thủ tục. Bạn phải sử dụng từ khóa ByRef để truyền một thông số tham chiếu như trong ví dụ sau:

VB.NET

Code:
        Sub MakeDeposit(ByRef num2 As Integer)        
End Sub
VB không có từ khóa cho các thông số out. Tuy nhiên, bạn có thể sử dụng đặc tính <Out> để đại diện cho các thông số out. Ví dụ:

VB.NET

Code:
        Imports System.Runtime.InteropServices        

Sub MakeDeposit(<Out()> ByRef num1 As Integer)
End Sub
Mã lệnh này khai báo thông số num1 trong MakeDeposit là một thông số out. Phiên bản C# đơn giản hơn, vì nó cung cấp một từ khóa để tự động thêm đặc tính này. Trong C#, nếu bạn đánh dấu một thông số là out, hàm phải gán giá trị cho thông số đó trước khi trả về, nếu không thì trình biên dịch sẽ thông báo lỗi. Nhưng trong VB, bạn có thể áp dụng đặc tính này cho một thông số ByRef hay cho một thông số ByVal. Trường hợp sau là sai nhưng trình biên dịch không bắt lỗi.

1.8 Truyền thông số hàm

Trong C#, nếu một hàm chứa các thông số ref, bạn phải sử dụng từ khóa ref trước mỗi đối số tham chiếu khi gọi hàm. Tương tự cho các thông số out, từ khóa out phải xuất hiện trước bất cứ đối số nào ứng với một thông số out. Cũng trong C#, không hợp lệ khi truyền một giá trị trực kiện làm đối số cho thông số ref hay out (chẳng hạn, bạn không thể truyền một số cho một thông số ref int). Bất cứ biến nào mà bạn truyền làm đối số ref cũng phải được khởi tạo trước khi gọi phương thức. Đoạn mã sau minh họa cho điều này:

C#.NET

Code:
        static void DoSomething(int x, ref int y, out int z)        
{
z=45;
}

static void Main(string[] args)
{
int y=4; // Bạn phải khai báo và khởi tạo biến.
int z;
// Sử dụng ref và out trước đối số ref và out.
DoSomething(5,ref y,out z);
}
Trong VB, bạn không phải sử dụng từ khóa trước các đối số của phương thức, cho dù chúng là ByVal, ByRef, hay <Out> ByRef. Ví dụ sau trình bày cách gọi hàm với các thông số ByRef trong VB.NET:

VB.NET

Code:
        Imports System.Runtime.InteropServices        

Module Module1
Sub DoSomething(ByVal x, ByRef y, <Out()> ByRef z)
z = 45
End Sub

Sub Main()
Dim y As Integer
Dim z As Integer

' y và z không cần được khởi tạo vì VB tự động khởi tạo các biến.
DoSomething(5, y, z)
' Sẽ hợp lệ trong VB.NET khi truyền giá trị trực kiện cho ByRef.
DoSomething(5, 10, 20)
End Sub
End Module
Chú ý rằng không nhất thiết phải sử dụng ByRef trước các đối số ByRef hoặc khởi tạo giá trị cho các biến đối số, bởi vì VB tự động khởi tạo các biến cục bộ. VB cũng cho phép bạn truyền giá trị trực kiện cho các thông số ByRef.
1.9 Thông số tùy chọn

Trong VB, bạn chỉ định các thông số tùy chọn như sau:

VB.NET

Code:
                  Sub MakeDeposit(Optional ByVal x As Integer=10)                  
End Sub
Optional có nghĩa là thông số có thể được lược bỏ. Nói cách khác, bạn có thể gọi MakeDeposit(20) hay MakeDeposit(). Nếu thông số được lược bỏ, giá trị mặc định (là 10 trong khai báo MakeDeposit ở trên) sẽ được sử dụng. Các giá trị mặc định phải là các hằng bởi vì nếu caller lược bỏ giá trị, trình biên dịch sẽ sử dụng giá trị mặc định. Do đó, lúc thực thi, nó xuất hiện như thể caller không lược bỏ giá trị. Khả năng lược bỏ các thông số khi gọi phương thức là đặc trưng của trình biên dịch VB. Ví dụ, nếu bạn viết một lớp trong VB với một phương thức có thông số tùy chọn, và sau đó sử dụng lớp này trong C#. Mã lệnh C# không thể lược bỏ thông số đó trong lời gọi.

Bạn có thể định nghĩa một thông số tùy chọn trong C# cũng giống như sử dụng một đặc tính. Tuy nhiên, trong C#, thông số sẽ không là tùy chọn. Nếu lớp C# được sử dụng trong chương trình VB, mã lệnh VB có thể lược bỏ thông số tùy chọn. Trong trường hợp này, giá trị của nó sẽ là 0 hay Nothing tùy thuộc vào kiểu biến, vì không có cách nào để chỉ định giá trị mặc định thông qua các đặc tính trong C#. Đoạn mã sau trình bày cách định nghĩa một phương thức với một thông số tùy chọn trong C#:

C#.NET

Code:
                  using System.Runtime.InteropServices;                  
public void MakeDeposit([Optional] int Amount) {}
.10 Danh sách thông số

Trong C# và VB, bạn có thể khai báo một thông số là một danh sách thông số (hay một mảng thông số)—một thông số có thể nhận một số lượng các đối số biến, tất cả cùng kiểu; hoặc một mảng với một số lượng các phần tử biến. Đoạn mã sau trình bày cách định nghĩa một mảng danh sách thông số trong C# và cách gọi phương thức có chứa nó:

C#.NET

Code:
    // Định nghĩa (trong một lớp).    
public void MakeDeposit(params int[] Amount) {}

// Gọi phương thức (trong một hàm).
Account acct = new Account();
// Gọi phương thức với nhiều đối số.
acct.MakeDeposit(50,100,20,30);
// Gọi phương thức không có đối số.
acct.MakeDeposit();
// Gọi phương thức với một mảng đối số.
int[] Amounts = {50,100,20,30};
acct.MakeDeposit(Amounts);
Đoạn mã trên gọi phương thức MakeDeposit ba lần: với 4 đối số, không đối số nào, và với một mảng đối số. Với bộ thực thi .NET, việc gọi MakeDeposit đơn giản là nhận một mảng số nguyên. Nếu bạn truyền nhiều đối số, trình biên dịch phát sinh mã lệnh để tạo ra một mảng và gán các giá trị cho nó, sau đó gọi MakeDeposit bằng cách truyền mảng giá trị này.

Dưới đây là đoạn mã tương đương trong VB:

VB.NET

Code:
    ' Định nghĩa (trong một lớp).    
Sub MakeDeposit(ParamArray Amount As Integer())
End Sub

' Gọi phương thức (trong một hàm).
Dim acct As New Account
' Gọi phương thức với nhiều đối số.
acct.MakeDeposit(50,100,20,30)
' Gọi phương thức không có đối số.
acct.MakeDeposit()
' Gọi phương thức với một mảng đối số.
Dim amts As Integer() = {50,100,20,30}
acct.MakeDeposit(amts)
1.11 Khai báo phương thức

Trong C#, tất cả phương thức đều là hàm. Một số hàm không trả về giá trị (void), ví dụ:

C#.NET

Code:
    public void MakeDeposit(int Amount) {}  
VB phân biệt hai loại phương thức: thủ tục (Sub) và hàm (Function). Thủ tục là phương thức không trả về giá trị. Khi một chương trình VB được biên dịch, thủ tục được chuyển thành hàm không trả về giá trị, giống như C#. Đoạn mã sau trình bày một thủ tục và một hàm VB.NET:

VB.NET

Code:
    Sub MakeDeposit(ByVal Amount As Integer)    
End Sub

Function IsOpen(ByVal AcctID As Integer) As Boolean
End Function
Chú ý rằng trong một hàm, bạn cần thêm As sau danh sách thông số, tiếp theo là kiểu trả về.

1.12 Trả về các thông số xuất

Cả C# và VB.NET đều có từ khóa return để trả về giá trị của một hàm và thoát khỏi hàm. Đoạn mã sau minh họa cách sử dụng từ khóa này:

C#.NET

Code:
    public class Person    
{
int m_Age = 10;

// Sử dụng return với một thông số.
public int GetAge()
{
return m_Age;
}

public void Speak()
{
if (m_Age < 1)
return;
// Làm gì đó khác tại đây.
}
}
Hàm GetAge trả về nội dung của trường m_Age, hàm Speak không trả về giá trị.
VB có một cách khác để trả về các thông số nhằm tương thích với các phiên bản VB trước. Bạn chỉ việc thiết lập tên hàm thành giá trị trả về (chú ý rằng: làm như thế sẽ không thoát khỏi hàm một cách tự động).

VB.NET

Code:
    Public Class Person    
Dim m_Age As Integer = 10

' Sử dụng return với một thông số.
Function GetAge() As Integer
Return m_Age
End Function

Sub Speak()
If m_Age < 1 Then Return
' Làm gì đó khác tại đây.
End Sub
1.13 Khởi động chương trình

Tất cả các chương trình EXE đều bắt đầu với một thủ tục Main. VB.NET có một tính năng cho phép dự án Windows Form chỉ định form khởi động thay vì thủ tục Main. Tuy vậy, ngay cả trong trường hợp này, chương trình cũng bắt đầu với một thủ tục Main (xem mục 3.3 để thấy cách làm việc).

Trong C#, Main (chữ M viết hoa) là một thủ tục tĩnh (static) của lớp. Trong VB.NET, Main là một thủ tục chia sẻ (Shared) của lớp. Trong VB.NET, Main cũng có thể nằm trong một Module. (Module là một lớp mà tất cả các phương thức đều là Shared, xem mục B.1.17 để biết chi tiết).

Cả C# và VB đều cho phép bạn viết thủ tục Main theo ba cách khác nhau. Ở dạng đơn giản nhất, bạn có thể viết thủ tục Main không có thông số. Ví dụ:

C#.NET

Code:
class App
{
static void Main()
{
}
}
VB.NET

Code:
Class App
Shared Sub Main()
End Sub
End Class
Bạn cũng có thể viết thủ tục Main với một thông số là mảng kiểu chuỗi. Mảng này chứa các đối số dòng lệnh được sử dụng lúc thực thi chương trình. Ví dụ, người dùng có thể thực thi chương trình như sau:
program.exe param1 param2 /param3 "param4 param5"

Dưới đây là ví dụ cho cách viết thủ tục Main như thế:
C#.NET

Code:
class App
{
static void Main(string[] args)
{
foreach(string arg in args)
{
System.Console.WriteLine(arg);
}
}
}
VB.NET

Code:
Class App
Shared Sub Main(ByVal args As String())
Dim arg As String
For Each arg In args
System.Console.WriteLine(arg)
Next
End Sub
End Class
Trong cách viết này, args là mảng chuỗi chứa các đối số dòng lệnh của chương trình. Các đối số dòng lệnh không bao gồm tên chương trình, chúng là các chuỗi theo sau tên chương trình. Mỗi đối số được phân cách bằng một khoảng trắng. Để có một chuỗi chứa khoảng trắng làm đối số, bạn phải thêm dấu ngoặc kép bao quanh nó. Đoạn mã trên xuất tất cả các đối số dòng lệnh ra cửa sổ Console. Giả sử chúng ta sử dụng dòng lệnh được mô tả ở trên, kết xuất như sau:

param1
param2
/param3
param4 param5

Bạn có thể có cách viết thứ ba cho thủ tục Main là một hàm trả về một số nguyên. Cách này có thể lấy thông số là một mảng chuỗi hoặc không có thông số. Số nguyên này là do lập trình viên định nghĩa. Do đó, bạn phải định nghĩa các giá trị có nghĩa. Thông thường, trả về 0 là thành công, khác 0 là có lỗi. Sau đây là ví dụ:

C#.NET

Code:
class App
{
static int Main()
{
return 0;
}
}
VB.NET

Code: Chọn hết
Class App
Shared Function Main() As Integer
Return 0
End Function
End Class
Nhằm tạo tính tương thích lùi, VB cũng có hàm Command cho phép bạn lấy về các đối số dòng lệnh ở dạng một chuỗi đơn. Ví dụ:

VB.NET

Code:
Imports Microsoft.VisualBasic

Class App
Shared Sub Main()
Dim args As String = Command()
System.Console.WriteLine(args)
End Sub
End Class
1.14 Thoát khỏi chương trình, phương thức, hay vòng lặp

VB.NET cung cấp nhiều câu lệnh để thoát khỏi một chương trình, phương thức, hay vòng lặp. Để thoát khỏi chương trình, bạn sử dụng câu lệnh End. Việc đặt End ở đâu trong mã lệnh sẽ làm cho chương trình kết thúc tại đó. Ví dụ:

VB.NET

Code:
Module App
Sub CheckSecurity(ByVal sID As String)
If sID = "" Then
End
End If
End Sub
Sub Main()
CheckSecurity("")
End Sub
End Module
C# không có phương thức tương đương để thoát khỏi chương trình. Tuy nhiên, cả VB và C# đều có thể sử dụng phương thức System.Environment.Exit. Dưới đây là ví dụ sử dụng phương thức Exit trong C#:

C#.NET

Code:
class App
{
static void CheckSecurity(string sID)
{
if (sID == "") System.Environment.Exit(1);
}

static void Main(string[] Args)
{
CheckSecurity("");
}
}
VB có một số câu lệnh để thoát khỏi phương thức, bao gồm Exit Sub, Exit Function, và Exit Property. Một ví dụ với Exit Function như sau:

VB.NET

Code:
Function MakeDeposit(ByVal Amount As Integer) As Integer
If Amount < 0 Then
Exit Function
End If
m_Balance += Amount
Return m_Balance
End Function
C# không có các phương thức tương đương. Tuy nhiên, điều này có thể được thực hiện bằng câu lệnh return. Thực tế, đó là những gì VB thực hiện bên trong.
VB.NET cũng có các phương thức để thoát khỏi vòng lặp, bao gồm Exit Do (cho vòng lặp Do-While) và Exit For (cho vòng lặp For-Next). Ví dụ:

VB.NET

Class People
Dim Total As Integer
Sub FillAuditorium()
Dim iCount As Integer
For iCount = 1 To 500
Total += iCount
If Total > 250 Then
Exit For
End If
Next
System.Console.WriteLine(iCount)
End Sub
End Class

C# có câu lệnh tương đương là break. Câu lệnh break sử dụng cho vòng lặp for, vòng lặp while và câu lệnh switch. Đoạn mã sau minh họa cách sử dụng break để thoát khỏi một phương thức:

C#.NET

class People
{
int Total;

public void FillAuditorium()
{
int iCount;
for (iCount = 1; iCount <= 500; iCount++)
{
Total += iCount;
if (Total > 250)
break;
}
System.Console.WriteLine(iCount);
}
}
Một tính năng của C# nhưng không có trong VB.NET là câu lệnh continue. Câu lệnh continue cho phép tiếp tục vòng lặp. Đoạn mã sau minh họa cách sử dụng continue:

C#.NET

public class Person
{
string LastName;
int Age;

public static void SearchPeople(Person[] arr, int Age)
{
for (int i=0; i < arr.Length; i++)
{
if (arr[i].Age != Age)
continue;
System.Console.WriteLine(arr[i].LastName);
}
}
}
Trong đoạn mã trên, vòng lặp trong hàm SearchPeople duyệt qua một mảng Person để tìm kiếm những người với tuổi cho trước. Câu lệnh if so sánh tuổi của người hiện tại với tuổi mong muốn. Nếu không bằng nhau, mã lệnh gọi continue để tiếp tục vòng lặp và trở về dòng lệnh đầu tiên trong vòng lặp.

1.15 Tầm vực thành viên

Khi khai báo các thành viên của lớp như trường, phương thức, thuộc tính, sự kiện, lớp lồng bên trong, v.v…, C# mặc định cho các thành viên này là private, còn VB thì mặc định cho các thành viên này (trừ những trường được khái báo bằng Dim) là public.

Bảng sau trình bày các từ khóa được sử dụng trong mỗi ngôn ngữ để chỉ tầm vực của một thành viên lớp:


Code: Chọn hết
C# VB.NET Chú thích

public Public Mặc định trong VB
private Private Mặc định trong C#
internal Friend
protected Protected
protected internal Protected Friend

1.16 Phương thức tĩnh và chia sẻ

Phương thức tĩnh là phương thức không được gắn vào một thể hiện cụ thể của một lớp. Nói cách khác, bạn có thể gọi phương thức tĩnh mà không cần tạo một thể hiện của lớp. Cũng vậy, trường tĩnh là trường không phụ thuộc vào thể hiện của lớp.

Hạn chế của các phương thức tĩnh là chúng chỉ có thể gọi các phương thức tĩnh khác, và chỉ có thể sử dụng các trường tĩnh. Chúng không thể gọi các phương thức thể hiện hay sử dụng các trường thể hiện mà chưa tạo ra thể hiện của lớp. Đoạn mã sau minh họa các trường và các phương thức tĩnh:

C#.NET

class Account
{
public static int TotalAccounts;
int m_ID;

public static int GetNextAccountID()
{
return TotalAccounts;
}

public Account()
{
m_ID = GetNextAccountID();
TotalAccounts++;
}
}
Lớp Account có hai trường. Thứ nhất là TotalAccounts, được chỉ định là tĩnh (tất cả các trường và hàm được chỉ định là public cho thuận tiện, các trường tĩnh không cần là public). Thứ hai là m_ID, đây là một trường thể hiện.

Đoạn mã trên cũng định nghĩa một phương thức tĩnh là GetNextAccountID. Nếu xem xét mã lệnh, bạn sẽ thấy các hàm thể hiện (như là hàm khởi dựng của lớp) có thể gọi các hàm tĩnh. Các hàm thể hiện cũng có thể truy xuất các trường tĩnh. Tuy nhiên, sẽ không hợp lệ khi một hàm tĩnh gọi các hàm thể hiện hay sử dụng các trường thể hiện. Nếu một hàm tĩnh cần gọi một phương thức thể hiện, nó phải tạo một thể hiện trước, sau đó gọi phương thức thể hiện.

Trong C#, để sử dụng các thành viên tĩnh từ bên ngoài lớp, bạn phải sử dụng tên lớp. Ví dụ, nếu muốn truy xuất hàm GetNextAccountID hay trường TotalAccounts, bạn thực hiện như sau:

C#.NET

class App
{
static void Main(string[] args)
{
int ID = Account.GetNextAccountID();
}
}
Sẽ không hợp lệ trong C# khi gọi một phương thức tĩnh hay sử dụng một trường tĩnh thông qua một biến thể hiện. Đoạn mã sau sẽ có lỗi biên dịch:

C#.NET

class App
{
static void Main(string[] args)
{
Account acct = new Account();
int ID = acct.GetNextAccountID(); // Lỗi.
}
}
VB cũng hỗ trợ các trường và các hàm tĩnh. VB sử dụng từ khóa Shared để chỉ định các thành viên tĩnh. Dưới đây là đoạn mã VB tương đương:

VB.NET

Class Account
Shared TotalAccounts As Integer
Dim m_ID As Integer

Shared Function GetNextAccountID() As Integer
return TotalAccounts
End Function

Sub New()
m_ID = GetNextAccountID()
TotalAccounts+=1
End Sub
End Class
Cũng giống như trong C#, các hàm chia sẻ trong VB chỉ có thể gọi các phương thức chia sẻ khác và sử dụng các trường chia sẻ. Tuy nhiên, các hàm thể hiện có thể sử dụng bất kì các trường chia sẻ và gọi bất kì các phương thức chia sẻ nào.

VB cho phép bạn gọi một phương thức chia sẻ hay sử dụng một trường chia sẻ bằng cách sử dụng một biến trỏ tới một thể hiện của lớp, như ví dụ sau:

VB.NET

Class App
Shared Sub Main()
' Hợp lệ trong cả hai ngôn ngữ.
Dim ID As Integer = Account.GetNextAccountID()

Dim Acct As New Account()
' Hợp lệ trong VB, không hợp lệ trong C#.
ID = Acct.GetNextAccountID()
End Sub
End Class
Trong ví dụ trên, sẽ hợp lệ khi gọi hàm GetNextAccountID bằng cách sử dụng tên lớp hay một thể hiện của lớp Account.

1.17 Lớp và đơn thể

VB.NET hỗ trợ các đơn thể mã lệnh, giúp lập trình viên viết các thư viện hàm toàn cục. Ví dụ:

VB.NET

Module App
Sub Main()
End Sub
End Module
Trình biên dịch VB chuyển một đơn thể thành một lớp, trong đó tất cả thành viên được chỉ định là Shared (static trong C#). Lớp được tạo ra là NotInheritable (sealed). Vì mỗi thành viên trong một đơn thể là Shared, bạn không thể thêm các hàm khởi dựng thể hiện vào đơn thể, chỉ được thêm một hàm khởi dựng chia sẻ.

Điều này không có trong C#, nhưng lập trình viên C# có thể mô phỏng một đơn thể bằng cách viết một lớp sealed với tất cả các phương thức và trường được chỉ định là static.

Thông thường, khi khai báo một phương thức chia sẻ trong một lớp, bạn phải sử dụng tên lớp cộng với phương thức để gọi nó, ví dụ:

VB.NET

Class Math
Shared Function Add(Num1 As Integer, Num2 As Integer) As Integer
End Function
End Class

Module App
Sub Main()
System.Console.WriteLine(Math.Add(3,4))
End Sub
End Module
Để gọi phương thức Add, bạn phải viết Math.Add. Trong VB, nếu phương thức là một phần của đơn thể, bạn có thể lược bỏ tên đơn thể:

VB.NET

Module Math
Function Add(Num1 As Integer, Num2 As Integer) As Integer
End Function
End Module

Module App
Sub Main()
System.Console.WriteLine(Add(3,4))
End Sub
End Module
Trong trường hợp này, bạn chỉ cần gọi phương thức Add. Điều này hoàn toàn đúng miễn là trình biên dịch có thể báo phương thức Add nào được gọi. Nếu bạn có hai đơn thể mà có cùng phương thức với cùng chữ ký, bạn phải chỉ rõ tên đầy đủ bằng cách thêm tên đơn thể, như thể bạn đang gọi phương thức chia sẻ từ một lớp.

Nếu đang viết một lớp trong C# để được sử dụng trong VB.NET, và muốn nó giống một đơn thể, bạn có thể chỉ định mọi thành viên trong lớp là static, sau đó tham chiếu đến assembly Microsoft.VisualBasic.dll và thêm đặc tính StandardModule (thuộc không gian tên Microsoft.VisualBasic.CompilerServices) vào lớp của bạn như sau:

C#.NET

[Microsoft.VisualBasic.CompilerServices.StandardMod ule]
public class Math
{
public static int Add(int num1, int num2)
{
return num1+num2;
}
}
Sau đó, một dự án VB có thể tham chiếu hàm Add một cách trực tiếp mà không cần tên lớp.

1.18 Câu lệnh if

Cả hai ngôn ngữ đều có câu lệnh điều kiện if. Tuy nhiên, cú pháp và ngữ nghĩa thì khác nhau giữa hai ngôn ngữ. Trong C#, câu lệnh điều kiện phải nằm trong dấu ngoặc đơn như sau:

C#.NET

if (x > 10)
DoSomething();
Chú ý, if là chữ thường, có dấu ngoặc đơn bao quanh câu lệnh điều kiện, không cần có Then như trong VB. Trong ví dụ trên, câu lệnh if chỉ thực hiện một tác vụ. Nếu có nhiều tác vụ để thực hiện, chúng được đặt trong dấu ngoặc nhọn như sau:

C#.NET

if (x < 10)
{
DoTask1();
DoTask2();
}
Nếu muốn thêm một mệnh đề ngược lại, bạn phải sử dụng từ khóa else (chữ thường) như sau:

C#.NET

if (x < 10)
{
DoTask1();
DoTask2();
}
else
{
DoOtherTask1();
DoOtherTask2();
}
Nếu câu lệnh else của bạn cần kiểm tra một điều kiện khác, bạn thêm câu lệnh điều kiện if đó vào mệnh đề else như sau:

C#.NET

if (x < 10)
{
DoTask1();
DoTask2();
}
else if (x > 10)
{
DoOtherTask1();
DoOtherTask2();
}
else
{
DoNothing();
}
Trong VB, cú pháp có khác một chút. VB sử dụng If và cần có từ khóa Then như sau:

VB.NET

If x > 10 Then DoSomething()
Không cần thiết phải có dấu ngoặc đơn bao quanh câu lệnh điều kiện. Giống như trong C#, câu lệnh If có thể thực hiện một hay nhiều tác vụ:
VB.NET
' Khi sử dụng "End If", "Then" là tùy chọn nhưng VS.NET thêm nó vào (mặc định).
If x < 10
DoTask1()
DoTask2()
End If
Thay vì bao quanh khối tác vụ bằng dấu ngoặc nhọn, VB sử dụng câu lệnh End If ở cuối khối. Mệnh đề ngược lại có thể được chỉ định bằng từ khóa Else:

VB.NET

If x < 10 Then
DoTask1()
DoTask2()
Else
DoOtherTask1()
DoOtherTask2()
End If
Trong trường hợp này, End If sau khối Else. Nếu mệnh đề ngược lại của bạn cần có điều kiện If khác, bạn không thể viết như trong C#. Thay vào đó, bạn phải sử dụng từ khóa ElseIf cho điều kiện thứ hai như sau:

VB.NET

If x < 10 Then
DoTask1()
DoTask2()
ElseIf x > 10 Then
DoOtherTask1()
DoOtherTask2()
Else
DoNothing()
End If
Khi nối các mệnh đề trong câu lệnh if, cả hai ngôn ngữ sử dụng các biểu tượng khác nhau để đại diện cho các toán tử. Bảng sau trình bày các toán tử được sử dụng trong mỗi ngôn ngữ:


VB.NET C# Toán tử

And && Và
Or || Hoặc
Not ! Phủ định
= == Bằng
Số lượt đọc:  413  -  Cập nhật lần cuối:  23/06/2008 04:12:25 PM
Bài đã đăng:
 Trang chủ | Giới thiệu | Liên hệ BQT | Tìm kiếm