Skip to content

2. Podstawy języka VB.NET

2.1. Wprowadzenie

Na początku traktujemy VB.NET jako klasyczny język programowania. Kwestie związane z obiektami omówimy w dalszej części.

W programie występują dwa rodzaje elementów

  • dane
  • instrukcje, które nimi operują

Zazwyczaj staramy się oddzielić dane od instrukcji:

2.2. Dane z VB.NET

VB.NET wykorzystuje następujące typy danych:

  1. liczby całkowite, rzeczywiste i dziesiętne
  1. znaki i ciągi znaków
  2. wartości logiczne
  3. daty
  4. obiekty

2.2.1. Wstępnie zdefiniowane typy danych

Typ VB
Typ .NET – odpowiednik
Rozmiar
Zakres wartości
Boolean
System.Boolean
2 bajty
True lub False.
Bajt
System.Byte
1 bajt
od 0 do 255 (bez znaku).
Znak
System.Char
2 bajty
Od 0 do 65 535 (bez znaku).
Data
System.DateTime
8 bajtów
Od 0:00:00 1 stycznia 0001 r. do 23:59:59 31 grudnia 9999 r.
Liczba dziesiętna
System.Decimal
16 bajtów
Od 0 do +/-79 228 162 514 264 337 593 543 950 335 bez miejsc po przecinku; od 0 do +/-7,9228162514264337593543950335 z 28 miejscami po przecinku; najmniejsza liczba różna od zera to +/-0,0000000000000000000000000001 (+/-1E-28).
Double
System.Double
8 bajtów
od -1,79769313486231E+308 do
-4,94065645841247E-324 dla wartości ujemnych; od 4,94065645841247E-324 do 1,79769313486231E+308 dla wartości dodatnich.
Liczba całkowita
System.Int32
4 bajty
od -2 147 483 648 do 2 147 483 647.
Long
System.Int64
8 bajtów
od -9 223 372 036 854 775 808 do 9 223 372 036 854 775 807.
Obiekt
System.Object
4 bajty
W zmiennej typu Object można przechowywać dowolny typ.
Short
System.Int16
2 bajty
od -32 768 do 32 767.
Single
System.Single
4 bajty
od -3,402823E+38 do -1,401298E-45 dla wartości ujemnych; od 1,401298E-45 do 3,402823E+38 dla wartości dodatnich.
Ciąg znaków
System.String (klasa)
 
Od 0 do około 2 miliardów znaków Unicode.

Z powyższej tabeli wynika, że istnieją dwa możliwe typy dla liczby całkowitej 32-bitowej: Integer i System.Int32. Oba typy są zamienne. To samo dotyczy pozostałych typów VB i ich odpowiedników na platformie .NET. Oto przykładowy program:


Module types
    Sub Main()
        ' liczby całkowite
        Dim var1 As Integer = 100
        Dim var2 As Long = 10000000000L
        Dim var3 As Byte = 100
        Dim var4 As Short = 4
        ' liczby rzeczywiste
        Dim var5 As Decimal = 4.56789D
        Dim var6 As Double = 3.4
        Dim var7 As Single = -0.000103F
        ' data
        Dim var8 As Date = New Date(2003, 1, 1, 12, 8, 4)
        ' wartość logiczna
        Dim var9 As Boolean = True
        ' znak
        Dim var10 As Char = "A"c
        ' ciąg znaków
        Dim var11 As String = "abcde"
        ' obiekt
        Dim var12 As Object = New Object
        ' wyświetlenia
        Console.Out.WriteLine("var1=" + var1.ToString)
        Console.Out.WriteLine("var2=" + var2.ToString)
        Console.Out.WriteLine("var3=" + var3.ToString)
        Console.Out.WriteLine("var4=" + var4.ToString)
        Console.Out.WriteLine("var5=" + var5.ToString)
        Console.Out.WriteLine("var6=" + var6.ToString)
        Console.Out.WriteLine("var7=" + var7.ToString)
        Console.Out.WriteLine("var8=" + var8.ToString)
        Console.Out.WriteLine("var9=" + var9.ToString)
        Console.Out.WriteLine("var10=" + var10)
        Console.Out.WriteLine("var11=" + var11)
        Console.Out.WriteLine("var12=" + var12.ToString)
    End Sub
End Module

Wykonanie programu daje następujące wyniki:

var1=100
var2=10000000000
var3=100
var4=4
var5=4,56789
var6=3,4
var7=-0,000103
var8=01/01/2003 12:08:04
var9=True
var10=A
var11=abcde
var12=System.Object

2.2.2. Zapis danych literałowych

Integer
145, -7, &FF (szesnastkowo)
Long
100000L
Double
134,789, -45E-18 (-45 × 10⁻¹⁸)
Single
134.789F, -45E-18F (-45 10-18)
Decimal
100000D
Char
„A”c
String
„dzisiaj”
Boolean
prawda, fałsz
date
New Date(2003, 1, 1) dla daty 01.01.2003

Należy zwrócić uwagę na następujące kwestie:

  • 100000L, litera L oznacza, że liczba jest traktowana jako liczba całkowita typu long
  • 134.789F, litera F oznacza, że liczba jest traktowana jako liczba rzeczywista o pojedynczej precyzji
  • 100000D, litera D oznacza, że liczba jest traktowana jako liczba zmiennoprzecinkowa
  • „A”c, aby przekształcić ciąg znaków „A” w znak „A”
  • Ciąg znaków jest ujęty w znak ". Jeśli ciąg ma zawierać znak ", należy go powtórzyć, tak jak w "abcd""e", aby przedstawić ciąg [abcd"e].

2.2.3. Deklaracja danych

2.2.3.1. Rola deklaracji

Program operuje na danych charakteryzujących się nazwą i typem. Dane te są przechowywane w pamięci. Podczas kompilacji programu kompilator przypisuje każdej danym miejsce w pamięci określone adresem i rozmiarem. Czyni to na podstawie deklaracji wprowadzonych przez programistę. Ponadto deklaracje te pozwalają kompilatorowi wykrywać błędy programistyczne. Na przykład operacja x=x*2 zostanie uznana za błędną, jeśli x jest ciągiem znaków.

2.2.3.2. Deklaracja stałych

Składnia deklaracji stałej jest następująca:

const identyfikator as typ=wartość

na przykład [const PI as double=3.141592]. Po co deklarować stałe?

  1. Czytanie programu będzie łatwiejsze, jeśli nadamy stałej znaczącą nazwę: [const taux_tva as single=0.186F]
  2. Modyfikacja programu będzie łatwiejsza, jeśli „stała” ulegnie zmianie. Tak więc w powyższym przypadku, jeśli stawka VAT wzrośnie do 33%, jedyną zmianą, jaką trzeba będzie wprowadzić, będzie zmiana instrukcji definiującej jej wartość: [const taux_tva as single=0.336F]. Gdyby w programie użyto bezpośrednio wartości 0,186, konieczna byłaby modyfikacja wielu instrukcji.

2.2.3.3. Deklaracja zmiennych

Zmienna jest identyfikowana przez nazwę i odnosi się do typu danych. W nazwie VB.NET nie rozróżnia się wielkich i małych liter. Zatem zmienne FIN i fin są identyczne. Zmienne można zainicjować podczas ich deklaracji. Składnia deklaracji jednej lub kilku zmiennych jest następująca:

dim zmienna1, zmienna2, ..., zmienna n as identyfikator_typu

gdzie identificateur_de_type jest typem predefiniowanym lub typem zdefiniowanym przez programistę.

2.2.4. Konwersje między liczbami a ciągami znaków

nombre -> chaîne
nombre.ToString lub "" & liczba lub CType(liczba, String)
objet -> chaîne
objet.ToString
chaine -> Integer
Integer.Parse(ciąg znaków) lub Int32.Parse
chaîne -> Long
Long.Parse (łańcuch) lub Int64.Parse
chaîne -> Double
Double.Parse (łańcuch)
chaîne -> Single
Single.Parse (ciąg znaków)

Konwersja ciągu znaków na liczbę może się nie powieść, jeśli ciąg ten nie reprezentuje prawidłowej liczby. W takim przypadku generowany jest błąd krytyczny zwany wyjątkiem o nazwie VB.NET. Błąd ten można obsłużyć za pomocą następującej klauzuli try/catch:

try
        appel de la fonction susceptible de générer l'exception
 catch e as Exception
        traiter l'exception e
end try
instruction suivante

Jeśli funkcja nie generuje wyjątku, przechodzi się do następnej instrukcji, w przeciwnym razie przechodzi się do treści klauzuli catch, a następnie do następnej instrukcji. Do kwestii obsługi wyjątków powrócimy w późniejszym terminie. Poniżej przedstawiono program ilustrujący główne techniki konwersji między liczbami a ciągami znaków. W tym przykładzie funkcja wyświetla na ekranie wartość swojego parametru. Tak więc affiche(S) wyświetla na ekranie wartość S.


' dyrektywy
Option Strict On

' importowane przestrzenie nazw
Imports System

' moduł testowy
Module Module1

    Sub Main()
        ' procedura główna
        ' dane lokalne
        Dim S As String
        Const i As Integer = 10
        Const l As Long = 100000
        Const f As Single = 45.78F
        Dim d As Double = -14.98

        ' liczba --> ciąg znaków
        affiche(CType(i, String))
        affiche(CType(l, String))
        affiche(CType(f, String))
        affiche(CType(d, String))

        'wartość logiczna --> ciąg znaków
        Const b As Boolean = False
        affiche(b.ToString)

        ' ciąg znaków --> liczba całkowita
        Dim i1 As Integer = Integer.Parse("10")
        affiche(i1.ToString)
        Try
            i1 = Integer.Parse("10.67")
            affiche(i1.ToString)
        Catch e As Exception
            affiche("Erreur [10.67] : " + e.Message)
        End Try

        ' ciąg znaków --> long
        Dim l1 As Long = Long.Parse("100")
        affiche("" + l1.ToString)
        Try
            l1 = Long.Parse("10.675")
            affiche("" & l1)
        Catch e As Exception
            affiche("Erreur [10.675] : " + e.Message)
        End Try

        ' ciąg znaków --> double
        Dim d1 As Double = Double.Parse("100,87")
        affiche(d1.ToString)
        Try
            d1 = Double.Parse("abcd")
            affiche("" & d1)
        Catch e As Exception
            affiche("Erreur [abcd] : " + e.Message)
        End Try

        ' ciąg znaków --> single
        Dim f1 As Single = Single.Parse("100,87")
        affiche(f1.ToString)
        Try
            d1 = Single.Parse("abcd")
            affiche(f1.ToString)
        Catch e As Exception
            affiche("Erreur [abcd] : " + e.Message)
        End Try
    End Sub

    ' wyświetla
    Public Sub affiche(ByVal S As String)
        Console.Out.WriteLine("S=" + S)
    End Sub
End Module

Otrzymane wyniki są następujące:

S=10
S=100000
S=45,78
S=-14,98
S=False
S=10
S=Erreur [10.67] : Le format de la chaîne d'entrée est incorrect.
S=100
S=Erreur [10.675] : Le format de la chaîne d'entrée est incorrect.
S=100,87
S=Erreur [abcd] : Le format de la chaîne d'entrée est incorrect.
S=100,87
S=Erreur [abcd] : Le format de la chaîne d'entrée est incorrect.

Należy zauważyć, że liczby rzeczywiste w postaci ciągu znaków muszą być zapisane z przecinkiem, a nie kropką. W związku z tym należy zapisać: Dim d As Double = -14.98, ale Dim d1 As Double = Double.Parse("100,87")

2.2.5. Tablice danych

Tablica VB.NET to obiekt służący do gromadzenia danych tego samego typu pod jednym identyfikatorem. Jej deklaracja wygląda następująco:

Dim Tablica(n) as typ lub Dim Tablica() as typ = New typ(n) {}

gdzie n jest indeksem ostatniego elementu tablicy. Składnia Tableau(i) odnosi się do danych o numerze i, gdzie i należy do przedziału [0,n]. Każde odwołanie do danych o numerze Tableau(i), gdzie i nie należy do przedziału [0,n], spowoduje wyjątek. Tablicę można zainicjować jednocześnie z jej zadeklarowaniem. W takim przypadku nie ma potrzeby podawania numeru ostatniego elementu.


        Dim entiers() As Integer = {0, 10, 20, 30}

Tablice posiadają właściwość Length, która określa liczbę elementów tablicy. Oto przykładowy program:


Module tab0
    Sub Main()
        ' pierwszą tablicę
        Dim tab0(5) As Integer
        For i As Integer = 0 To UBound(tab0)
            tab0(i) = i
        Next
        For i As Integer = 0 To UBound(tab0)
            Console.Out.WriteLine("tab0(" + i.ToString + ")=" + tab0(i).tostring)
        Next

        ' druga tabela
        Dim tab1() As Integer = New Integer(5) {}
        For i As Integer = 0 To tab1.Length - 1
            tab1(i) = i * 10
        Next
        For i As Integer = 0 To tab1.Length - 1
            Console.Out.WriteLine("tab1(" + i.ToString + ")=" + tab1(i).tostring)
        Next
    End Sub
End Module

oraz jego wykonanie:

tab0(0)=0
tab0(1)=1
tab0(2)=2
tab0(3)=3
tab0(4)=4
tab0(5)=5
tab1(0)=0
tab1(1)=10
tab1(2)=20
tab1(3)=30
tab1(4)=40
tab1(5)=50

Dwuwymiarową tablicę można zadeklarować w następujący sposób:

Dim Tablica(n,m) as Typ lub Dim Tablica(,) as Typ = New Typ(n,m) {}

gdzie n+1 to liczba wierszy, a m+1 to liczba kolumn. Składnia Tablica(i,j) oznacza element o indeksie j w wierszu i tablicy Tablica. Tablicę dwuwymiarową można również zainicjować w momencie jej deklaracji:


        Dim réels(,) As Double = {{0.5, 1.7}, {8.4, -6}}

Liczbę elementów w każdym z wymiarów można uzyskać za pomocą metody GetLenth(i), gdzie i=0 oznacza wymiar odpowiadający pierwszemu indeksowi, i=1 – wymiar odpowiadający drugiemu indeksowi, … Oto przykładowy program:


Module Module2
    Sub Main()
        ' pierwsza tabela
        Dim tab0(2, 1) As Integer
        For i As Integer = 0 To UBound(tab0)
            For j As Integer = 0 To tab0.GetLength(1) - 1
                tab0(i, j) = i * 10 + j
            Next
        Next
        For i As Integer = 0 To UBound(tab0)
            For j As Integer = 0 To tab0.GetLength(1) - 1
                Console.Out.WriteLine("tab0(" + i.ToString + "," + j.ToString + ")=" + tab0(i, j).tostring)
            Next
        Next

        ' druga tabela
        Dim tab1(,) As Integer = New Integer(2, 1) {}
        For i As Integer = 0 To tab1.GetLength(0) - 1
            For j As Integer = 0 To tab1.GetLength(1) - 1
                tab1(i, j) = i * 100 + j
            Next
        Next
        For i As Integer = 0 To tab1.GetLength(0) - 1
            For j As Integer = 0 To tab1.GetLength(1) - 1
                Console.Out.WriteLine("tab1(" + i.ToString + "," + j.ToString + ")=" + tab1(i, j).tostring)
            Next
        Next
    End Sub
End Module

oraz wyniki jego wykonania:

tab0(0)=0
tab0(1)=1
tab0(2)=2
tab0(3)=3
tab0(4)=4
tab0(5)=5
tab1(0)=0
tab1(1)=10
tab1(2)=20
tab1(3)=30
tab1(4)=40
tab1(5)=50

Tablica tablic jest deklarowana w następujący sposób:

Dim Tablica(n)() as Typ lub Dim Tablica()() as Typ = new Typ(n)()

Powyższa deklaracja tworzy tablicę o n+1 wierszach. Każdy element Tablica(i) jest odwołaniem do tablicy jednowymiarowej. Tablicy te nie są tworzone podczas powyższej deklaracji. Poniższy przykład ilustruje tworzenie tablicy tablic:


         ' tabela tabel
        Dim noms()() As String = New String(3)() {}
         ' inicjalizacja
        For i = 0 To noms.Length - 1
            noms(i) = New String(i) {}
            For j = 0 To noms(i).Length - 1
                noms(i)(j) = "nom" & i & j
            Next
        Next

W tym przypadku noms(i) jest tablicą zawierającą i+1 elementów. Ponieważ noms(i) jest tablicą, noms(i).Length stanowi liczbę jej elementów. Oto przykład łączący trzy rodzaje tablic, które właśnie omówiliśmy:


' dyrektywy
Option Strict On
Option Explicit On 

' importy
Imports System

' klasa testowa
Module test
    Sub main()
        ' zainicjowana tablica jednowymiarowa
        Dim entiers() As Integer = {0, 10, 20, 30}
        Dim i As Integer
        For i = 0 To entiers.Length - 1
            Console.Out.WriteLine("entiers[" & i & "]=" & entiers(i))
        Next

        ' zainicjowana tablica dwuwymiarowa
        Dim réels(,) As Double = {{0.5, 1.7}, {8.4, -6}}
        Dim j As Integer
        For i = 0 To réels.GetLength(0) - 1
            For j = 0 To réels.GetLength(1) - 1
                Console.Out.WriteLine("réels[" & i & "," & j & "]=" & réels(i, j))
            Next
        Next

        ' tablica tablic
        Dim noms()() As String = New String(3)() {}

        ' inicjalizacja
        For i = 0 To noms.Length°- 1
            noms(i) =°New String(i) {}
            For j = 0 To noms(i).Length - 1
                noms(i)(j) = "nom" & i & j
            Next
        Next

        ' wyświetlanie
        For i = 0 To noms.Length°- 1
            For j = 0 To noms(i).Length - 1
                Console.Out.WriteLine("noms[" & i & "][" & j & "]=" & noms(i)(j))
            Next
        Next
    End Sub
End Module

Podczas wykonywania otrzymujemy następujące wyniki:

entiers[0]=0
entiers[1]=10
entiers[2]=20
entiers[3]=30
réels[0,0]=0,5
réels[0,1]=1,7
réels[1,0]=8,4
réels[1,1]=-6
noms[0][0]=nom00
noms[1][0]=nom10
noms[1][1]=nom11
noms[2][0]=nom20
noms[2][1]=nom21
noms[2][2]=nom22
noms[3][0]=nom30
noms[3][1]=nom31
noms[3][2]=nom32
noms[3][3]=nom33

2.3. Podstawowe instrukcje dotyczące VB.NET

Rozróżnia się

1 polecenia podstawowe wykonywane przez komputer.

2 instrukcje sterujące przebiegiem programu.

Instrukcje podstawowe stają się jasne, gdy przyjrzymy się budowie mikrokomputera i jego urządzeń peryferyjnych.

  1. odczyt informacji z klawiatury

  2. przetwarzanie informacji

  3. zapisywanie informacji na ekranie

  4. odczyt informacji z pliku na dysku

  5. zapisywanie informacji do pliku na dysku

2.3.1. Zapis na ekranie

Istnieją różne instrukcje zapisywania na ekranie:

Console.Out.WriteLine(expression)
Console.WriteLine(expression)
Console.Error.WriteLine (expression)

gdzie expression oznacza dowolny typ danych, który można przekonwertować na ciąg znaków w celu wyświetlenia na ekranie. W dotychczasowych przykładach używaliśmy wyłącznie instrukcji Console.Out.WriteLine(wyrażenie).

Klasa System.Console zapewnia dostęp do operacji zapisu na ekranie (Write, WriteLine). Klasa Console posiada dwie właściwości: Out i Error, które są strumieniami zapisu typu StreamWriter:

  • Console.WriteLine() jest równoważne Console.Out.WriteLine() i zapisuje dane do strumienia Out, zwykle powiązanego z ekranem.
  • Funkcja Console.Error.WriteLine() zapisuje dane do strumienia Error, który zazwyczaj jest również powiązany z ekranem.

Strumienie Out i Error są domyślnie powiązane z ekranem. Można je jednak przekierować do plików tekstowych w trakcie wykonywania programu, co omówimy wkrótce.

2.3.2. Odczyt danych wprowadzonych z klawiatury

Strumień danych pochodzących z klawiatury jest reprezentowany przez obiekt Console.In typu StreamReader. Ten typ obiektów umożliwia odczytanie wiersza tekstu za pomocą metody ReadLine:


        Dim ligne As String = Console.In.ReadLine()

Wpisany na klawiaturze wiersz jest zapisywany w zmiennej ligne i może być następnie przetwarzany przez obiekt programme.Le. Strumień wejściowy (In) może zostać przekierowany do pliku, podobnie jak strumienie wyjściowe (Out) i błędów (Error).

2.3.3. Przykład operacji wejścia-wyjścia

Oto krótki program ilustrujący operacje wejścia i wyjścia z klawiatury/ekranu:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

' moduł
Module io1
    Sub Main()
        ' zapis do strumienia Out
        Dim obj As New Object
        Console.Out.WriteLine(("" & obj.ToString))

        ' zapis do strumienia Error
        Dim i As Integer = 10
        Console.Error.WriteLine(("i=" & i))

        ' odczyt linii wprowadzonej z klawiatury
        Console.Out.Write("Tapez une ligne : ")
        Dim ligne As String = Console.In.ReadLine()
        Console.Out.WriteLine(("ligne=" + ligne))
    End Sub
End Module

oraz wyniki wykonania:

System.Object
i=10
Tapez une ligne : ceci est un essai
ligne=ceci est un essai

Instrukcje


        Dim obj As New Object
        Console.Out.WriteLine(obj.ToString)

służą jedynie pokazaniu, że dowolny obiekt może zostać wyświetlony. Nie będziemy tutaj wyjaśniać znaczenia tego, co jest wyświetlane.

2.3.4. Przekierowanie wejścia/wyjścia

W systemie DOS/Windows istnieją trzy standardowe urządzenia o nazwach:

  1. standardowe urządzenie wejściowe – domyślnie oznacza klawiaturę i ma numer 0
  2. standardowe urządzenie wyjściowe – domyślnie oznacza ekran i ma numer 1
  3. standardowe urządzenie błędów – domyślnie oznacza ekran i ma numer 2

W systemie VB.NET strumień zapisu Console.Out zapisuje dane na urządzeniu 1, strumień zapisu Console.Error zapisuje dane na urządzeniu 2, a strumień odczytu Console.In odczytuje dane z urządzenia 0. Uruchamiając program w oknie DOS w systemie Windows, można określić, które urządzenia będą oznaczone jako 0, 1 i 2 dla uruchamianego programu. Rozważmy następujący wiersz poleceń:

pg arg1 arg2 .. argn

Korzystając z opcji programu pg, można przekierować standardowe urządzenia wejścia/wyjścia do plików:

0<in.txt
standardowy strumień wejściowy nr 0 jest przekierowywany do pliku in.txt. W programie strumień Console.In będzie zatem pobierał dane z pliku in.txt.
 
1>out.txt
przekierowuje strumień wyjściowy nr 1 do pliku out.txt. W związku z tym w programie strumień Console.Out zapisze swoje dane do pliku out.txt
  
1>>out.txt
to samo, ale zapisane dane są dodawane do aktualnej zawartości pliku out.txt.
  
2>error.txt
przekierowuje strumień nr 2 do pliku error.txt. Powoduje to, że w programie strumień Console.Error zapisze swoje dane do pliku error.txt
  
2>>error.txt
to samo, ale zapisane dane są dodawane do aktualnej zawartości pliku error.txt.
  
1>out.txt 2>error.txt
Urządzenia 1 i 2 są przekierowane do plików
  

Należy zauważyć, że aby przekierować strumienie wejścia/wyjścia programu pg do plików, nie ma potrzeby modyfikowania programu pg. To właśnie program OS określa charakter urządzeń 0, 1 i 2. Rozważmy następujący program:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

' przekierowania
Module console2
    Sub Main()
        ' odczyt strumienia In
        Dim data As String = Console.In.ReadLine()
        ' zapis strumienia Out
        Console.Out.WriteLine(("écriture dans flux Out : " + data))
        ' zapis strumienia Error
        Console.Error.WriteLine(("écriture dans flux Error : " + data))
    End Sub
End Module

Skompilujmy ten program:

dos>vbc es2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
Copyright (C) Microsoft Corporation 1987-2002. Tous droits réservés.

dos>dir
24/02/2004  15:39                  416 es2.vb
11/03/2004  08:20                3 584 es2.exe

Przeprowadźmy pierwsze uruchomienie:

dos>es2.exe
un premier test
écriture dans flux Out : un premier test
écriture dans flux Error : un premier test

Poprzednie uruchomienie nie przekierowuje żadnego ze standardowych strumieni wejścia/wyjścia: In, Out, Error. Teraz przekierujemy wszystkie trzy strumienie. Strumień In zostanie przekierowany do pliku in.txt, strumień Out do pliku out.txt, a strumień Error do pliku error.txt. Przekierowanie to odbywa się w wierszu poleceń w postaci

dos>es2.exe 0<in.txt 1>out.txt 2>error.txt

Wykonanie daje następujące wyniki:

dos>more in.txt
un second test

dos>es2.exe 0<in.txt 1>out.txt 2>error.txt

dos>more out.txt
écriture dans flux Out : un second test

dos>more error.txt
écriture dans flux Error : un second test

Wyraźnie widać, że przepływy Out i Error nie zapisują danych na tych samych urządzeniach.

2.3.5. Przypisanie wartości wyrażenia do zmiennej

W tym miejscu skupiamy się na operacji variable=expression. Wyrażenie może być typu: arytmetycznego, relacyjnego, boolowskiego lub znakowego.

2.3.5.1. Lista operatorów

Działanie
Element języka
Arithmétique
^, –, *, /, \, Mod, +, =
Assignation
=, ^=, *=, /=, \=, +=, -=, &=
Comparaison
=, <>, <, >, <=, >=, Like, Is
Concaténation
&, +
Opérations logiques/de bits
Not, And, Or, Xor, AndAlso, OrElse
Opérations diverses
AddressOf, GetType

2.3.5.2. Wyrażenie arytmetyczne

Operatory wyrażeń arytmetycznych są następujące:

Arithmétique
^, –, *, /, \, Mod, +, =

+: dodawanie, -: odejmowanie, *: mnożenie, /: dzielenie zmiennoprzecinkowe, \: iloraz dzielenia całkowitego, Mod: reszta z dzielenia całkowitego, ^: potęgowanie. Zatem następujący program:


' operatory arytmetyczne
Module operateursarithmetiques
    Sub Main()
        Dim i, j As Integer
        i = 4 : j = 3
        Console.Out.WriteLine(i & "/" & j & "=" & (i / j))
        Console.Out.WriteLine(i & "\" & j & "=" & (i \ j))
        Console.Out.WriteLine(i & " mod " & j & "=" & (i Mod j))

        Dim r1, r2 As Double
        r1 = 4.1 : r2 = 3.6
        Console.Out.WriteLine(r1 & "/" & r2 & "=" & (r1 / r2))
        Console.Out.WriteLine(r1 & "^2=" & (r1 ^ 2))
        Console.Out.WriteLine(Math.Cos(3))
    End Sub
End Module

daje następujące wyniki:

4/3=1,33333333333333
4\3=1
4 mod 3=1
4,1/3,6=1,13888888888889
4,1^2=16,81
-0,989992496600445

Istnieje wiele funkcji matematycznych. Oto kilka z nich:


Public Shared Function Sqrt(ByVal d As Double ) As Double
pierwiastek kwadratowy

[Visual Basic]
Public Shared Function Cos(ByVal d As Double ) As Double
cosinus

Public Shared Function Sin(ByVal a As Double) As Double
Sinus

[Visual Basic]
Public Shared Function Tan(ByVal a As Double) As Double
Tangens

[Visual Basic]
Public Shared Function Pow(ByVal x As Double,ByVal y As Double) As Double
x do potęgi y (x>0)

[Visual Basic]
Public Shared Function Exp(ByVal d As Double) As Double
Funkcja wykładnicza

[Visual Basic]
Overloads Public Shared Function Log( ByVal d As Double ) As Double
Logarytm naturalny

Overloads Public Shared Function Abs(ByVal value As Double ) As Double
wartość bezwzględna
....
 

Wszystkie te funkcje są zdefiniowane w klasie o nazwie .NET o nazwie Math. Korzystając z nich, należy poprzedzić je nazwą klasy, w której są zdefiniowane. W ten sposób napiszemy:

        Dim r1, r2 As Double
        r2 = Math.Sqrt(9)
        r1 = Math.Cos(3)

Pełna definicja klasy Math jest następująca:

E 
Oznacza podstawę logarytmu naturalnego określoną przez stałą e.
  
PI 
Oznacza stosunek obwodu koła do jego średnicy, określony przez stałą π.
  
Abs 
Przedefiniowana. Zwraca wartość bezwzględną podanej liczby.
 
Acos 
Zwraca kąt, którego cosinus jest równy podanej liczbie.
 
Asin 
Zwraca kąt, którego sinus jest równy podanej liczbie.
 
Atan 
Zwraca kąt, którego tangensem jest podana liczba.
 
Atan2 
Zwraca kąt, którego tangens jest ilorazem dwóch podanych liczb.
 
BigMul
Generuje iloczyn całkowity dwóch liczb 32-bitowych.
 
Ceiling 
Zwraca najmniejszą liczbę całkowitą większą lub równą podanej liczbie.
 
Cos 
Zwraca cosinus podanego kąta.
 
Cosh 
Zwraca cosinus hiperboliczny podanego kąta.
 
DivRem
Przedefiniowana. Zwraca iloraz dwóch liczb, przekazując resztę jako parametr wyjściowy.
 
Exp 
Zwraca e podniesione do podanej potęgi.
 
Floor 
Zwraca największą liczbę całkowitą nie większą niż podana liczba.
 
IEEERemainder 
Zwraca resztę z dzielenia podanej liczby przez inną liczbę.
 
Log 
Przedefiniowana. Zwraca logarytm podanej liczby.
 
Log10 
Zwraca logarytm dziesiętny podanej liczby.
 
Max 
Przeładowana. Zwraca większą z dwóch podanych liczb.
 
Min 
Przepełnienie. Zwraca mniejszą z dwóch liczb.
 
Pow 
Zwraca podaną liczbę podniesioną do podanej potęgi.
 
Round 
Przedefiniowana. Zwraca liczbę najbliższą podanej wartości.
 
Sign 
Przedefiniowana. Zwraca wartość wskazującą znak liczby.
 
Sin 
Zwraca sinus podanego kąta.
 
Sinh 
Zwraca sinus hiperboliczny podanego kąta.
 
Sqrt 
Zwraca pierwiastek kwadratowy z podanej liczby.
 
Tan 
Zwraca tangens podanego kąta.
 
Tanh 
Zwraca tangens hiperboliczny podanego kąta.
 

Gdy funkcja jest określana jako „przeciążona”, oznacza to, że istnieje dla różnych typów parametrów. Na przykład funkcja Abs(x) istnieje dla x typu Integer, Long, Decimal, Single, Float. Dla każdego z tych typów istnieje osobna definicja funkcji Abs. Mówi się wówczas, że jest ona przeciążona.

2.3.5.3. Priorytety przy obliczaniu wyrażeń arytmetycznych

Priorytet operatorów podczas obliczania wyrażenia arytmetycznego jest następujący (od najwyższego do najniższego):

Kategoria
Operatory
Primaire
Wszystkie wyrażenia bez operatorów: funkcje, nawiasy
Élévation à la puissance
^
Négation unaire
+, -
Multiplication
*, /
Division par un entier
\
Modulo
Mod
Addition
+, -

2.3.5.4. Wyrażenia relacyjne

Dostępne są następujące operatory:

Comparaison
=, <>, <, >, <=, >=, Like, Is

=: równe, <>: nie równe, <: mniejsze niż (ściśle), >: większe niż (ściśle), <=: mniejsze lub równe, >=: większe lub równe, Like: pasuje do wzorca, Is: tożsamość obiektów. Wszystkie te operatory mają ten sam priorytet. Są one obliczane od lewej do prawej. Wynikiem wyrażenia relacyjnego jest wartość logiczna.

Porównanie ciągów znaków: rozważmy następujący program:


' przestrzenie nazw
Imports System

Module string1
    Sub main()
        Dim ch1 As Char = "A"c
        Dim ch2 As Char = "B"c
        Dim ch3 As Char = "a"c
        Console.Out.WriteLine("A<B=" & (ch1 < ch2))
        Console.Out.WriteLine("A<a=" & (ch1 < ch3))
        Dim chat As String = "chat"
        Dim chien As String = "chien"
        Dim chaton As String = "chaton"
        Dim chat2 As String = "CHAT"
        Console.Out.WriteLine("chat<chien=" & (chat < chien))
        Console.Out.WriteLine("chat<chaton=" & (chat < chaton))
        Console.Out.WriteLine("chat<CHAT=" & (chat < chat2))
        Console.Out.WriteLine("chaton like chat*=" & ("chaton" Like "chat*"))
    End Sub
End Module

oraz wynik jego wykonania:

A<B=True
A<a=True
chat<chien=True
chat<chaton=True
chat<CHAT=False
chaton like chat*=True

Niech C1 i C2 będą dwoma znakami. Można je porównać za pomocą operatorów: <, <=, =, <>, >, >=. Porównywane są wówczas ich wartości Unicode, które są liczbami. Zgodnie z kolejnością Unicode zachodzą następujące relacje:

spacja < .. < „0” < „1” < .. < „9” < .. < „A” < „B” < .. < „Z” < .. < „a” < „b” < .. < „z”

Ciągi znaków są porównywane znak po znaku. Pierwsza napotkana nierówność między dwoma znakami powoduje nierówność o tym samym znaczeniu w odniesieniu do ciągów znaków. Mając te wyjaśnienia, czytelnik powinien przeanalizować wyniki poprzedniego programu.

2.3.5.5. Wyrażenia boolowskie

Dostępne są następujące operatory:

Opérations logiques/de bits
Not, And, Or, Xor, AndAlso, OrElse

Not: i logiczne, Or: lub logiczne, Not: negacja, Xor: lub wykluczające.

op1 AndAlso op2: jeśli op1 jest fałszywe, op2 nie jest obliczane, a wynik jest fałszywy.

op1 OrElse op2: jeśli op1 jest prawdziwe, op2 nie jest obliczane, a wynik jest prawdziwy.

Kolejność pierwszeństwa tych operatorów względem siebie jest następująca:

NOT logique
Not
AND logique
And, AndAlso
OR logique
Lub, OrElse
XOR logique
XOR

Wynikiem wyrażenia boolowskiego jest wartość logiczna.

2.3.5.6. Operacje bitowe

Z jednej strony mamy te same operatory co w przypadku operatorów boolowskich, o tej samej kolejności pierwszeństwa. Znajdują się tu również dwa operatory przesunięcia: << i >>. Niech i oraz j będą dwiema liczbami całkowitymi.

i<<n
przesuwa i o n bitów w lewo. Nowe bity to zera.
i>>n
przesuwa i o n bitów w prawo. Jeśli i jest liczbą całkowitą ze znakiem (signed char, int, long), bit znaku pozostaje zachowany.
i & j
wykonuje operację logicznego OR bit po bicie na i i j.
i | j
wykonuje operację logicznego OR bit po bicie między i a j (OU).
~i
zwiększa i o 1
i^j
tworzy OU EXCLUSIF z i i j

Oto następujący program:


Module operationsbit
    Sub main()
        ' operacje na bitach
        Dim i As Short = &H123F
        Dim k As Short = &H7123
        Console.Out.WriteLine("i<<4=" & (i << 4).ToString("X"))
        Console.Out.WriteLine("i>>4=" & (i >> 4).ToString("X"))
        Console.Out.WriteLine("k>>4=" & (k >> 4).ToString("X"))
        Console.Out.WriteLine("i and 4=" & (i And 4).ToString("X"))
        Console.Out.WriteLine("i or 4 =" & (i Or 4).ToString("X"))
        Console.Out.WriteLine("not i=" & (Not i).ToString("X"))
    End Sub
End Module

Jego wykonanie daje następujące wyniki:

i<<4=23F0
i>>4=123
k>>4=712
i and 4=4
i or k =123F
not i=EDC0

2.3.5.7. Operator powiązany z operacją przypisania

Można zapisać a+=b, co oznacza a=a+b. Lista operatorów, które można łączyć z operacją przypisania, jest następująca:

combinaison d'opérateurs
^=, *=, /=, \=, +=, -=, &=

2.3.5.8. Ogólna kolejność operacji

Kategoria
Operatory
Primaire
Wszystkie wyrażenia bez operatorów
Élévation à la puissance
^
Négation unaire
+, -
Multiplication
*, /
Division par un entier
\
Modulo
Mod
Addition
+, -
Concaténation
&
Déplacement
<<, >>
Relationnel
=, <>, <, >, <=, >=, Like, Is, TypeOf...Is
NOT logique
Not
AND logique
And, AndAlso
OR logique
Lub, OrElse
XOR logique
XOR

Gdy operand znajduje się pomiędzy dwoma operatorami o tej samej priorytecie, kolejność wykonywania operacji określa asocjatywność operatorów. Wszystkie operatory są asocjatywne z lewej strony, co oznacza, że operacje są wykonywane od lewej do prawej. Priorytet i asocjatywność można kontrolować za pomocą wyrażeń w nawiasach.

2.3.5.9. Konwersje typów

Istnieje szereg predefiniowanych funkcji umożliwiających konwersję jednego typu danych na inny. Ich lista przedstawia się następująco:

CBool,CByte,CChar,CDate,CDbl,CDec,CInt,CLng,CObj,CShort,CSng,CStr

Funkcje te przyjmują jako argument wyrażenie liczbowe lub ciąg znaków. Typ wyniku podano w poniższej tabeli:

funkcja
wynik
Zakres wartości parametru funkcji
CBool
Boolean
Dowolny prawidłowy ciąg znaków lub wyrażenie liczbowe.
CByte
Bajt
Od 0 do 255; ułamki są zaokrąglane.
CChar
Znak
Dowolny prawidłowy ciąg znaków; wartość może wynosić od 0 do 65 535.
CDate
Data
Dowolny prawidłowy zapis daty i godziny.
CDbl
Double
-1,79769313486231E+308 do
-4,94065645841247E-324 dla wartości ujemnych; od 4,94065645841247E-324 do 1,79769313486231E+308 dla wartości dodatnich.
CDec
Liczba dziesiętna
+/-79 228 162 514 264 337 593 543 950 335 dla liczb bez miejsc po przecinku. Zakres wartości liczb z 28 miejscami po przecinku wynosi
+/-7,9228162514264337593543950335. Najmniejsza liczba różna od zera to 0,0000000000000000000000000001.
CInt
Liczba całkowita
od -2 147 483 648 do 2 147 483 647; ułamki są zaokrąglane.
CLng
Liczba długa
od -9 223 372 036 854 775 808 do 9 223 372 036 854 775 807; ułamki są zaokrąglane.

CObj 
Obiekt
Dowolne prawidłowe wyrażenie.
CShort
Krótki
Od -32 768 do 32 767; ułamki są zaokrąglane.
CSng
Single
od -3,402823E+38 do -1,401298E-45 dla wartości ujemnych; od 1,401298E-45 do 3,402823E+38 dla wartości dodatnich.
CStr
Ciąg znaków
Wartości zwracane przez funkcję Cstr zależą od argumentu expression.

Oto przykładowy program:


Module conversion
    Sub main()
        Dim var1 As Boolean = CBool("true")
        Dim var2 As Byte = CByte("100")
        Dim var3 As Char = CChar("A")
        Dim var4 As Date = CDate("30 janvier 2004")
        Dim var5 As Double = CDbl("100,45")
        Dim var6 As Decimal = CDec("1000,67")
        Dim var7 As Integer = CInt("-30")
        Dim var8 As Long = CLng("456")
        Dim var9 As Short = CShort("-14")
        Dim var10 As Single = CSng("56,78")
        Console.Out.WriteLine("var1=" & var1)
        Console.Out.WriteLine("var2=" & var2)
        Console.Out.WriteLine("var3=" & var3)
        Console.Out.WriteLine("var4=" & var4)
        Console.Out.WriteLine("var5=" & var5)
        Console.Out.WriteLine("var6=" & var6)
        Console.Out.WriteLine("var7=" & var7)
        Console.Out.WriteLine("var8=" & var8)
        Console.Out.WriteLine("var9=" & var9)
        Console.Out.WriteLine("var10=" & var10)
    End Sub
End Module

oraz wyniki jego wykonania:

var1=True
var2=100
var3=A
var4=30/01/2004
var5=100,45
var6=1000,67
var7=-30
var8=456
var9=-14
var10=56,78

Można również użyć funkcji CType(expression, type), jak pokazano w poniższym programie:


Module ctype1
    Sub main()
        Dim var1 As Boolean = CType("true", Boolean)
        Dim var2 As Byte = CType("100", Byte)
        Dim var3 As Char = CType("A", Char)
        Dim var4 As Date = CType("30 janvier 2004", Date)
        Dim var5 As Double = CType("100,45", Double)
        Dim var6 As Decimal = CType("1000,67", Decimal)
        Dim var7 As Integer = CType("-30", Integer)
        Dim var8 As Long = CType("456", Long)
        Dim var9 As Short = CType("-14", Short)
        Dim var10 As Single = CType("56,78", Single)
        Dim var11 As String = CType("47,89", String)
        Dim var12 As String = 47.89.ToString
        Dim var13 As String = "" & 47.89
        Console.Out.WriteLine("var1=" & var1)
        Console.Out.WriteLine("var2=" & var2)
        Console.Out.WriteLine("var3=" & var3)
        Console.Out.WriteLine("var4=" & var4)
        Console.Out.WriteLine("var5=" & var5)
        Console.Out.WriteLine("var6=" & var6)
        Console.Out.WriteLine("var7=" & var7)
        Console.Out.WriteLine("var8=" & var8)
        Console.Out.WriteLine("var9=" & var9)
        Console.Out.WriteLine("var10=" & var10)
        Console.Out.WriteLine("var11=" & var11)
        Console.Out.WriteLine("var12=" & var12)
        Console.Out.WriteLine("var13=" & var13)
    End Sub
End Module

co daje następujące wyniki:

var1=True
var2=100
var3=A
var4=30/01/2004
var5=100,45
var6=1000,67
var7=-30
var8=456
var9=-14
var10=56,78
var11=47,89
var12=47,89
var13=47,89

2.4. Instrukcje dotyczące kontroli przebiegu programu

2.4.1. Zatrzymanie

Metoda Exit zdefiniowana w klasie Environment umożliwia zatrzymanie wykonywania programu:


[Visual Basic]
Public Shared Sub Exit(ByVal exitCode As Integer )

zatrzymuje bieżący proces i zwraca wartość exitCode do procesu nadrzędnego. Ten ostatni może wykorzystać wartość exitCode. W przypadku wartości DOS ta zmienna statusowa jest zwracana do DOS w zmiennej systemowej ERRORLEVEL, której wartość można sprawdzić w pliku wsadowym. W systemie Unix wartość exitCode jest przechwytywana przez zmienną $?.

    Environment.Exit(0)

przerwie wykonywanie programu z wartością stanu równą 0.

2.4.2. Prosta struktura wyboru

if condition then
    actions_alors
else
    actions_sinon
end if
  • każda akcja znajduje się w osobnym wierszu
  • klauzula else może nie występować.

Struktury wyboru można zagnieżdżać, jak pokazuje poniższy przykład:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module if1
    Sub main()
        Dim i As Integer = 10
        If i > 4 Then
            Console.Out.WriteLine(i & " est > " & 4)
        Else
            If i = 4 Then
                Console.Out.WriteLine(i & " est = " & 4)
            Else
                Console.Out.WriteLine(i & " est < " & 4)
            End If
        End If
    End Sub
End Module

Uzyskany wynik:

10 est > 4

2.4.3. Struktura przypadków

Składnia jest następująca:

select case expression
    case liste_valeurs1
        actions1
case liste_valeurs2
        actions2
...
case else
        actions_sinon
end select
  • Typ [expression] musi być jednym z następujących typów:
Boolean, Byte, Char, Date, Decimal, Double, Integer, Long, Object, Short, Single et String
  • klauzula [case else] może nie występować.
  • [liste_valeursi] to możliwe wartości wyrażenia. [listes_valeursi] reprezentuje listę warunków: warunek1, warunek2, ..., warunekx. Jeśli [expression] spełnia jeden z warunków, wykonywane są działania związane z klauzulą [liste_valeursi]. Warunki mogą mieć następującą postać:
  • val1 to val2: prawdziwe, jeśli [expression] należy do dziedziny [val1,val2]
  • val1: prawdziwe, jeśli [expression] jest równe val1
  • is > val1: prawdziwe, jeśli [expression] > val1. Słowo kluczowe [is] może nie występować
  • to samo dotyczy operatorów =, <, <=, >, >=, <>
  • wykonane zostaną tylko te akcje, które są związane z pierwszym sprawdzonym warunkiem.

Rozważmy następujący program:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module selectcase1
    Sub main()
        Dim i As Integer = 10
        Select Case i
            Case 1 To 4, 7 To 8
                Console.Out.WriteLine("i est dans l'intervalle [1,4] ou [7,8]")
            Case Is > 12
                Console.Out.WriteLine("i est > 12")
            Case Is < 15
                Console.Out.WriteLine("i est < 15")
            Case Is < 20
                Console.Out.WriteLine("i est < 20")
        End Select
    End Sub
End Module

Daje to następujące wyniki:

i est < 15

2.4.4. Struktura powtórzeń

2.4.4.1. Znana liczba powtórzeń


For counter [ As datatype ] = start To end [ Step step ]
   actions
Next [ counter ]

Operacje są wykonywane dla każdej wartości przyjmowanej przez zmienną [counter]. Rozważmy następujący program:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module for1
    Sub main()
        Dim somme As Integer = 0
        Dim résultat As String = "somme("
        For i As Integer = 0 To 10 Step 2
            somme += i
            résultat += " " + i.ToString
        Next
        résultat += ")=" + somme.ToString
        Console.Out.WriteLine(résultat)
    End Sub
End Module

Wyniki:

somme( 0 2 4 6 8 10)=30

Inną strukturą iteracji o znanej liczbie iteracji jest następująca:


For Each element [ As datatype ] In groupe
   [ actions ]
Next [ element ]
  • groupe to zbiór obiektów. Zbiorem obiektów, który już znamy, jest tablica
  • datatype jest typem obiektów w tej kolekcji. W przypadku tablicy byłby to typ elementów tablicy
  • element jest zmienną lokalną pętli, która będzie kolejno przyjmować wszystkie wartości z kolekcji.

Zatem poniższy kod:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module foreach1
    Sub main()
        Dim amis() As String = {"paul", "hélène", "jacques", "sylvie"}
        For Each nom As String In amis
            Console.Out.WriteLine(nom)
        Next
    End Sub
End Module

wyświetliłby:

paul
hélène
jacques
sylvie

2.4.4.2. Nieznana liczba powtórzeń

W tym przypadku istnieje wiele struktur w formacie VB.NET.


Do { While | Until } condition
   [ statements ]
Loop

Pętla jest wykonywana tak długo, jak długo warunek jest spełniony (while) lub do momentu, gdy warunek zostanie spełniony (until). Pętla może nigdy nie zostać wykonana.


Do
   [ statements ]
Loop { While | Until } condition

Pętla jest wykonywana tak długo, jak długo warunek jest spełniony (while) lub do momentu, gdy warunek zostanie spełniony (until). Pętla jest zawsze wykonywana co najmniej raz.


While condition
   [ statements ]
End While

Pętla jest wykonywana tak długo, jak długo warunek jest spełniony. Pętla może nigdy nie zostać wykonana. Poniższe pętle obliczają sumę pierwszych 10 liczb całkowitych.


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module boucles1
    Sub main()
        Dim i, somme As Integer
        i = 0 : somme = 0
        Do While i < 11
            somme += i
            i += 1
        Loop
        Console.Out.WriteLine("somme=" + somme.ToString)
        i = 0 : somme = 0
        Do Until i = 11
            somme += i
            i += 1
        Loop
        Console.Out.WriteLine("somme=" + somme.ToString)
        i = 0 : somme = 0
        Do
            somme += i
            i += 1
        Loop Until i = 11
        Console.Out.WriteLine("somme=" + somme.ToString)
        i = 0 : somme = 0
        Do
            somme += i
            i += 1
        Loop While i < 11
        Console.Out.WriteLine("somme=" + somme.ToString)
    End Sub
End Module
somme=55
somme=55
somme=55
somme=55

2.4.4.3. Instrukcje dotyczące zarządzania pętlą

exit do
wyjście z pętli do ... loop
exit for
wyjście z pętli for

2.5. Struktura programu VB.NET

Program VB.NET, który nie wykorzystuje klas zdefiniowanych przez użytkownika ani funkcji innych niż funkcja główna Main, może mieć następującą strukturę:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports espace1
Imports ....

Module nomDuModule
    Sub main()
....
    End Sub
End Module
  • Dyrektywa [Option Explicit on] wymusza deklarowanie zmiennych. W przypadku VB.NET nie jest to obowiązkowe. Zmienna niezadeklarowana ma wówczas typ Object.
  • Dyrektywa [Option Strict on] zabrania wszelkich konwersji typów danych, które mogą prowadzić do utraty danych, oraz wszelkich konwersji między typami liczbowymi a ciągami znaków. Należy wówczas wyraźnie korzystać z funkcji konwersji.
  • Program importuje wszystkie przestrzenie nazw, których potrzebuje. Nie wprowadziliśmy jeszcze tego pojęcia. W poprzednich programach często spotykaliśmy instrukcje typu:
        Console.Out.WriteLine(unechaine)

W rzeczywistości powinniśmy byli napisać:

        System.Console.Out.WriteLine(unechaine)

gdzie System to przestrzeń nazw zawierająca klasę [Console]. Importując przestrzeń nazw [System] za pomocą instrukcji Imports, VB.NET będzie ją systematycznie przeszukiwać, gdy napotka nieznaną klasę. Będzie powtarzać wyszukiwanie we wszystkich zadeklarowanych przestrzeniach nazw, aż znajdzie poszukiwaną klasę. Piszemy zatem:


' przestrzenie nazw
Imports System
....

        Console.Out.WriteLine(unechaine)

Przykładowy program mógłby wyglądać następująco:


' opcje
Option Explicit On 
Option Strict On

'przestrzenie nazw
Imports System

' moduł główny
Module main1
    Sub main()
        Console.Out.WriteLine("main1")
    End Sub
End Module

Ten sam program można zapisać w następujący sposób:


' opcje
Option Explicit On 
Option Strict On

'przestrzenie nazw
Imports System

' klasa testowa
Public Class main2
    Public Shared Sub main()
        Console.Out.WriteLine("main2")
    End Sub
End Class

W tym przypadku wykorzystujemy pojęcie klasy, które zostanie omówione w następnym rozdziale. Gdy taka klasa zawiera procedurę statyczną (shared) o nazwie main, zostaje ona wykonana. Wprowadzamy ten zapis tutaj, ponieważ język C#, będący odpowiednikiem VB.NET, zna wyłącznie pojęcie klasy, c.a.d, co oznacza, że każdy wykonywany kod musi koniecznie należeć do klasy. Pojęcie klasy należy do programowania obiektowego. Narzucanie go przy projektowaniu każdego programu jest nieco nieuzasadnione. Widać to tutaj w wersji 2 poprzedniego programu, gdzie jesteśmy zmuszeni do wprowadzenia pojęcia klasy i metody statycznej tam, gdzie nie jest to konieczne. Dlatego też w dalszej części będziemy wprowadzać pojęcie klasy tylko wtedy, gdy będzie to konieczne. W pozostałych przypadkach będziemy korzystać z pojęcia modułu, tak jak w wersji 1 powyżej.

2.6. Kompilacja i uruchomienie programu VB.NET

Kompilacja programu VB.NET wymaga jedynie pliku SDK.NET. Rozważmy następujący program:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module boucles1
    Sub main()
        Dim i, somme As Integer
        i = 0 : somme = 0
        Do While i < 11
            somme += i
            i += 1
        Loop
        Console.Out.WriteLine("somme=" + somme.ToString)
        i = 0 : somme = 0
        Do Until i = 11
            somme += i
            i += 1
        Loop
        Console.Out.WriteLine("somme=" + somme.ToString)
        i = 0 : somme = 0
        Do
            somme += i
            i += 1
        Loop Until i = 11
        Console.Out.WriteLine("somme=" + somme.ToString)
        i = 0 : somme = 0
        Do
            somme += i
            i += 1
        Loop While i < 11
        Console.Out.WriteLine("somme=" + somme.ToString)
    End Sub
End Module

Załóżmy, że znajduje się on w pliku o nazwie [boucles1.vb]. Aby go skompilować, postępujemy w następujący sposób:

dos>dir boucles1.vb
11/03/2004  15:55                  583 boucles1.vb

dos>vbc boucles1.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4
pour Microsoft (R) .NET Framework version 1.1.4322.573
Copyright (C) Microsoft Corporation 1987-2002. Tous droits réservés.

dos>dir boucles1.*
11/03/2004  16:04                  601 boucles1.vb
11/03/2004  16:04                3 584 boucles1.exe

Program vbc.exe to kompilator VB.NET. Tutaj znajdował się on w pliku PATH z pliku DOS:


dos>path
PATH=E:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE;E:\Program Files\Microsoft Visual Studio .NET 2003\VC7\BIN;E:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools;E:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\bin\prerelease;E:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\bin;E:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\bin;E:\WINNT\Microsoft.NET\Framework\v1.1.4322;e:\winnt\system32;e:\winnt;

dos>dir E:\WINNT\Microsoft.NET\Framework\v1.1.4322\vbc.exe
21/02/2003  10:20              737 280 vbc.exe

Kompilator [vbc] generuje plik .exe, który może być uruchomiony przez maszynę wirtualną .NET:

dos>boucles1
somme=55
somme=55
somme=55
somme=55

2.7. Przykład IMPOTS

Zamierzamy napisać program umożliwiający obliczenie podatku podatnika. Rozważamy uproszczony przypadek podatnika, który ma do zadeklarowania wyłącznie swoje wynagrodzenie:

  • obliczamy liczbę udziałów pracownika nbParts = nbEnfants/2 + 1, jeśli jest on osobą stanu wolnego, nbEnfants/2+2, jeśli jest żonaty, gdzie nbEnfants to liczba jego dzieci.
  • jeśli ma co najmniej troje dzieci, przysługuje mu dodatkowa połowa udziału
  • oblicza się jego dochód podlegający opodatkowaniu R = 0,72 * S, gdzie S to jego roczne wynagrodzenie
  • oblicza się jego współczynnik rodzinny QF = R / nbParts
  • oblicza się jego podatek I. Rozważmy następującą tabelę:
12620,0
0
0
13190
0,05
631
15640
0,1
1290,5
24 740
0,15
2072,5
31810
0,2
3309,5
39 970
0,25
4900
48360
0,3
6898,5
55790
0,35
9316,5
92970
0,4
12106
127 860
0,45
16754,5
151250
0,50
23147,5
172 040
0,55
30710
195 000
0,60
39312
0
0,65
49062

Każdy wiersz zawiera 3 pola. Aby obliczyć podatek I, należy znaleźć pierwszy wiersz, w którym QF <= pole1. Na przykład, jeśli QF = 23000, znajdziemy wiersz

    24740        0.15        2072.5

Podatek I wynosi wówczas 0,15*R – 2072,5*nbParts. Jeśli QF jest takie, że relacja QF <= pole1 nigdy nie jest spełniona, wówczas stosuje się współczynniki z ostatniego wiersza. W tym przypadku:

    0                0.65        49062

co daje podatek I = 0,65*R – 49062*nbParts. Odpowiedni program VB.NET wygląda następująco:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module impots
    ' ------------ main
    Sub Main()

        ' tabele danych niezbędne do obliczenia podatku
        Dim Limites() As Decimal = {12620D, 13190D, 15640D, 24740D, 31810D, 39970D, 48360D, 55790D, 92970D, 127860D, 151250D, 172040D, 195000D, 0D}
        Dim CoeffN() As Decimal = {0D, 631D, 1290.5D, 2072.5D, 3309.5D, 4900D, 6898.5D, 9316.5D, 12106D, 16754.5D, 23147.5D, 30710D, 39312D, 49062D}

        ' pobieramy stan cywilny
        Dim OK As Boolean = False
        Dim reponse As String = Nothing
        While Not OK
            Console.Out.Write("Etes-vous marié(e) (O/N) ? ")
            reponse = Console.In.ReadLine().Trim().ToLower()
            If reponse <> "o" And reponse <> "n" Then
                Console.Error.WriteLine("Réponse incorrecte. Recommencez")
            Else
                OK = True
            End If
        End While
        Dim Marie As Boolean = reponse = "o"

        ' liczba dzieci
        OK = False
        Dim NbEnfants As Integer = 0
        While Not OK
            Console.Out.Write("Nombre d'enfants : ")
            reponse = Console.In.ReadLine()
            Try
                NbEnfants = Integer.Parse(reponse)
                If NbEnfants >= 0 Then
                    OK = True
                Else
                    Console.Error.WriteLine("Réponse incorrecte. Recommencez")
                End If
            Catch
                Console.Error.WriteLine("Réponse incorrecte. Recommencez")
            End Try
        End While
        ' wynagrodzenie
        OK = False
        Dim Salaire As Integer = 0
        While Not OK
            Console.Out.Write("Salaire annuel : ")
            reponse = Console.In.ReadLine()
            Try
                Salaire = Integer.Parse(reponse)
                If Salaire >= 0 Then
                    OK = True
                Else
                    Console.Error.WriteLine("Réponse incorrecte. Recommencez")
                End If
            Catch
                Console.Error.WriteLine("Réponse incorrecte. Recommencez")
            End Try
        End While
        ' obliczanie liczby udziałów
        Dim NbParts As Decimal
        If Marie Then
            NbParts = CDec(NbEnfants) / 2 + 2
        Else
            NbParts = CDec(NbEnfants) / 2 + 1
        End If
        If NbEnfants >= 3 Then
            NbParts += 0.5D
        End If
        ' dochód podlegający opodatkowaniu
        Dim Revenu As Decimal
        Revenu = 0.72D * Salaire

        ' współczynnik rodzinny
        Dim QF As Decimal
        QF = Revenu / NbParts

        ' wyszukiwanie przedziału podatkowego odpowiadającego QF
        Dim i As Integer
        Dim NbTranches As Integer = Limites.Length
        Limites((NbTranches - 1)) = QF
        i = 0
        While QF > Limites(i)
            i += 1
        End While
        ' podatek
        Dim impots As Integer = CInt(i * 0.05D * Revenu - CoeffN(i) * NbParts)

        ' wyświetla się wynik
        Console.Out.WriteLine(("Impôt à payer : " & impots))
    End Sub
End Module

Program kompiluje się w oknie DOS za pomocą polecenia:

dos>vbc impots1.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573

dos>dir impots1.exe
24/02/2004  15:42                5 632 impots1.exe

W wyniku kompilacji powstaje plik wykonywalny impots.exe. Należy zauważyć, że plik impots.exe nie jest bezpośrednio wykonywalny przez procesor. W rzeczywistości zawiera on kod pośredni, który można wykonać wyłącznie na platformie .NET. Uzyskane wyniki są następujące:

dos>impots1
Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : 3
Salaire annuel : 200000
Impôt à payer : 16400
dos>impots1
Etes-vous marié(e) (O/N) ? n
Nombre d'enfants : 2
Salaire annuel : 200000
Impôt à payer : 33388
dos>impots1
Etes-vous marié(e) (O/N) ? w
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? q
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : q
Réponse incorrecte. Recommencez
Nombre d'enfants : 2
Salaire annuel : q
Réponse incorrecte. Recommencez
Salaire annuel : 1
Impôt à payer : 0

2.8. Argumenty programu głównego

Procedura główna Main może przyjmować jako parametr tablicę ciągów znaków:


    Sub main(ByVal args() As String)

Parametr args to tablica ciągów znaków, która przechwytuje argumenty przekazane w wierszu poleceń podczas wywołania programu.

  • args.Length to liczba elementów tablicy args
  • args(i) to element i tablicy

Jeśli uruchomimy program P za pomocą polecenia: P arg0 arg1 … argn i jeśli procedura Main programu P jest zadeklarowana w następujący sposób:


    Sub main(ByVal args() As String)

to otrzymamy arg(0)="arg0", arg(1)="arg1" … Oto przykład:


' wytyczne
Option Strict On
Option Explicit On 

' przestrzenie nazw
Imports System

Module arg
    Sub main(ByVal args() As String)
        ' liczba argumentów
        console.out.writeline("Il y a " & args.length & " arguments")
        Dim i As Integer
        For i = 0 To args.Length - 1
            Console.Out.WriteLine("argument n° " & i & "=" & args(i))
        Next
    End Sub
End Module

Wykonanie daje następujące wyniki:

dos>arg1 a b c
Il y a 3 arguments
argument n° 0=a
argument n° 1=b
argument n° 2=c

2.9. Wyliczenia

Wymiennik to typ danych, którego domena wartości stanowi zbiór stałych całkowitoliczbowych. Rozważmy program, który ma zarządzać ocenami z egzaminu. Jest ich pięć: „Zadowalająco”, AssezBien, „Dobrze”, TrèsBien, „Doskonale”. Można by zatem zdefiniować wymiennik dla tych pięciu stałych:


    Enum mention
        Passable
        AssezBien
        Bien
        TrésBien
        Excellent
    End Enum

Wewnętrznie te pięć stałych jest kodowanych za pomocą kolejnych liczb całkowitych, zaczynających się od 0 dla pierwszej stałej, 1 dla następnej itd. Zmienną można zadeklarować tak, aby przyjmowała te wartości z wyliczenia:


         ' zmienna przyjmująca wartości z wymienionej wyliczalnej
        Dim maMention As mention = mention.Passable

Można porównać zmienną z różnymi możliwymi wartościami z tej wyliczalnej listy:


         ' test z wartością z wyliczenia
        If (maMention = mention.Passable) Then
            Console.Out.WriteLine("Peut mieux faire")
        End If

Można uzyskać wszystkie wartości wyliczenia:


        For Each m In mention.GetValues(maMention.GetType)
            Console.Out.WriteLine(m)
        Next

Podobnie jak typ prosty Integer jest równoważny strukturze Int32, tak typ prosty Enum jest równoważny strukturze Enum. Klasa ta posiada metodę statyczną GetValues, która pozwala uzyskać wszystkie wartości typu wyliczeniowego przekazanego jako parametr. Parametr ten musi być obiektem typu Type, który jest klasą zawierającą informacje o typie danych. Typ zmiennej v uzyskuje się za pomocą funkcji v.GetType(). Zatem w tym przypadku funkcja maMention.GetType() zwraca obiekt Type z wyliczenia mentions, a funkcja Enum.GetValues(maMention.GetType()) zwraca listę wartości wyliczenia mentions.

Ilustruje to poniższy program:


' dyrektywy
Option Strict On
Option Explicit On 

' przestrzenie nazw
Imports System

Public Module enum2

    ' wyliczenie
    Enum mention
        Passable
        AssezBien
        Bien
        TrèsBien
        Excellent
    End Enum

    ' strona testowa
    Sub Main()

        ' zmienna pobierająca wartości z wymienionej listy wyliczeniowej
        Dim maMention As mention = mention.Passable

        ' wyświetlanie wartości zmiennej
        Console.Out.WriteLine("mention=" & maMention)

        ' test z wartością z wyliczenia
        If (maMention = mention.Passable) Then
            Console.Out.WriteLine("Peut mieux faire")
        End If

        ' lista wartości literałowych
        For Each m As mention In [Enum].GetValues(maMention.GetType)
            Console.Out.WriteLine(m.ToString)
        Next

        ' lista pełnych wpisów
        For Each m As Integer In [Enum].GetValues(maMention.GetType)
            Console.Out.WriteLine(m)
        Next
    End Sub
End Module

Wyniki wykonania są następujące:

dos>enum2
mention=0
Peut mieux faire
Passable
AssezBien
Bien
TrèsBien
Excellent
0
1
2
3
4

2.10. Obsługa wyjątków

Wiele funkcji VB.NET może generować wyjątki, czyli błędy. Gdy funkcja może wygenerować wyjątek, programista powinien go obsłużyć, aby uzyskać programy bardziej odporne na błędy: należy zawsze unikać niekontrolowanego „zawieszenia” aplikacji.

Obsługa wyjątku odbywa się zgodnie z poniższym schematem:

try
    appel de la fonction susceptible de générer l'exception
catch  e as Exception e)
    traiter l'exception e
end try
instruction suivante

Jeśli funkcja nie generuje wyjątku, przechodzi się do następnej instrukcji; w przeciwnym razie przechodzi się do treści klauzuli catch, a następnie do następnej instrukcji. Należy zwrócić uwagę na następujące kwestie:

  • e jest obiektem pochodnym typu Exception. Można być bardziej precyzyjnym, używając typów takich jak IOException, SystemException itp.: istnieje kilka rodzajów wyjątków. Pisząc catch e as Exception, wskazujemy, że chcemy obsłużyć wszystkie typy wyjątków. Jeśli kod klauzuli try może generować kilka typów wyjątków, możemy chcieć być bardziej precyzyjni, obsługując wyjątek za pomocą kilku klauzul catch:
try
    appel de la fonction susceptible de générer l'exception
catch e as IOException 
    traiter l'exception e
catch  e as SystemException
    traiter l'exception e
end try
instruction suivante
  • Do klauzul try/catch można dodać klauzulę finally:
try
    appel de la fonction susceptible de générer l'exception
catch  e as Exception
    traiter l'exception e
finally
    code exécuté après try ou catch
end try
instruction suivante

Niezależnie od tego, czy wystąpi wyjątek, czy nie, kod klauzuli finally zostanie zawsze wykonany.

  • W klauzuli catch może się zdarzyć, że nie będziemy chcieli korzystać z dostępnego obiektu Exception. Zamiast pisać catch e as Exception, piszemy wówczas catch.
  • Klasa Exception posiada właściwość Message, która zawiera komunikat opisujący wystąpiły błąd. Jeśli więc chcemy go wyświetlić, napiszemy:
catch e as Exception
    Console.Error.WriteLine("L'erreur suivante s'est produite : "+e.Message);
    ...
end try
  • Klasa Exception posiada metodę ToString, która zwraca ciąg znaków wskazujący typ wyjątku oraz wartość właściwości Message. Można zatem napisać:
catch  ex as Exception
    Console.Error.WriteLine("L'erreur suivante s'est produite : "+ex.ToString)
    ...
end try

Poniższy przykład przedstawia wyjątek wygenerowany w wyniku użycia nieistniejącego elementu tablicy:


' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System

Module tab1
    Sub Main()
        ' deklaracja i inicjalizacja tablicy
        Dim tab() As Integer = {0, 1, 2, 3}
        Dim i As Integer

        ' wyświetlanie tablicy za pomocą pętli for
        For i = 0 To tab.Length - 1
            Console.Out.WriteLine(("tab[" & i & "]=" & tab(i)))
        Next i

        ' wyświetlanie tablicy za pomocą pętli for each
        Dim élmt As Integer
        For Each élmt In tab
            Console.Out.WriteLine(élmt)
        Next élmt

        ' generowanie wyjątku
        Try
            tab(100) = 6
        Catch e As Exception
            Console.Error.WriteLine(("L'erreur suivante s'est produite : " & e.Message))
        End Try
    End Sub
End Module

Wykonanie programu daje następujące wyniki:

dos>exception1
tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
0
1
2
3
L'erreur suivante s'est produite : L'index se trouve en dehors des limites du tableau.

Oto kolejny przykład obsługi wyjątku spowodowanego przypisaniem ciągu znaków do liczby, gdy ciąg ten nie reprezentuje liczby:


' opcje
Option Strict On
Option Explicit On 

'importy
Imports System

Public Module console1
  Public Sub Main()
    ' Zapytanie o nazwę
    System.Console.Write("Nom : ")

        ' odczyt odpowiedzi
    Dim nom As String = System.Console.ReadLine()

        ' zapytanie o wiek
    Dim age As Integer
    Dim ageOK As Boolean = False
    Do While Not ageOK
      ' pytanie
      Console.Out.Write("âge : ")
      ' odczyt i weryfikacja odpowiedzi
      Try
        age = Int32.Parse(System.Console.ReadLine())
        If age < 0 Then Throw New Exception
        ageOK = True
      Catch
        Console.Error.WriteLine("Age incorrect, recommencez...")
      End Try
    Loop

        ' wyświetlenie końcowe
    Console.Out.WriteLine("Vous vous appelez [" & nom & "] et vous avez [" & age & "] ans")
  End Sub
End Module

Kilka wyników wykonania:

dos>console1
Nom : dupont
âge : 23
Vous vous appelez dupont et vous avez 23 ans
dos>console1
Nom : dupont
âge : xx
Age incorrect, recommencez...
âge : 12
Vous vous appelez dupont et vous avez 12 ans

2.11. Przekazywanie parametrów do funkcji

W tym miejscu zajmiemy się sposobem przekazywania parametrów do funkcji. Rozważmy funkcję:


    Sub changeInt(ByVal a As Integer)
        a = 30
        Console.Out.WriteLine(("Paramètre formel a=" & a))
    End Sub    

W definicji funkcji a nazywany jest parametrem formalnym. Znajduje się on tam wyłącznie na potrzeby definicji funkcji changeInt. Równie dobrze mógłby nosić nazwę b. Rozważmy teraz przykładowe wykorzystanie tej funkcji:


    Sub Main()
        Dim age As Integer = 20
        changeInt(age)
        Console.Out.WriteLine(("Paramètre effectif age=" & age))
    End Sub

W instrukcji changeInt(wiek) parametr rzeczywisty age przekaże swoją wartość do parametru formalnego a. Interesuje nas sposób, w jaki parametr formalny pobiera wartość odpowiadającego mu parametru rzeczywistego.

2.11.1. Przekazywanie przez wartość

Poniższy przykład pokazuje, że parametry funkcji/procedury są domyślnie przekazywane przez wartość: oznacza to, że wartość parametru rzeczywistego jest kopiowana do odpowiadającego mu parametru formalnego. Mamy do czynienia z dwoma odrębnymi jednostkami. Jeśli funkcja modyfikuje parametr formalny, parametr rzeczywisty pozostaje niezmieniony.


' opcje
Option Explicit On 
Option Strict On

' przekazywanie parametrów jako wartości do funkcji
Imports System

Module param1
    Sub Main()
        Dim age As Integer = 20
        changeInt(age)
        Console.Out.WriteLine(("Paramètre effectif age=" & age))
    End Sub

    Sub changeInt(ByVal a As Integer)
        a = 30
        Console.Out.WriteLine(("Paramètre formel a=" & a))
    End Sub
End Module

Otrzymane wyniki są następujące:

Paramètre formel a=30
Paramètre effectif age=20

Wartość 20 parametru rzeczywistego została skopiowana do parametru formalnego a. Ten ostatni został następnie zmodyfikowany. Parametr rzeczywisty pozostał natomiast niezmieniony. Ten sposób przekazywania nadaje się do parametrów wejściowych funkcji.

2.11.2. Przekazywanie przez odwołanie

W przypadku przekazywania przez odwołanie parametr rzeczywisty i parametr formalny stanowią jedną i tę samą jednostkę. Jeśli funkcja modyfikuje parametr formalny, modyfikowany jest również parametr rzeczywisty. W przypadku VB.NET przed parametrem formalnym musi znajdować się słowo kluczowe ByRef. Oto przykład:


' opcje
Option Explicit On 
Option Strict On

' przekazywanie parametrów przez wartość do funkcji
Imports System

Module param2
    Sub Main()
        Dim age As Integer = 20
        changeInt(age)
        Console.Out.WriteLine(("Paramètre effectif age=" & age))
    End Sub

    Sub changeInt(ByRef a As Integer)
        a = 30
        Console.Out.WriteLine(("Paramètre formel a=" & a))
    End Sub
End Module

oraz wyniki wykonania:

Paramètre formel a=30
Paramètre effectif age=30

Parametr rzeczywisty został dostosowany do zmiany parametru formalnego. Ten sposób przekazywania nadaje się do parametrów wyjściowych funkcji.