Visual Basic 2005 Almanach vb25al


Visual Basic 2005.
Almanach
Tim Patrick, Steven Roman, Ron Petrusha, Paul Lomax
Tłumaczenie: Mikołaj Szczepaniak
ISBN: 83-246-0475-8
Tytuł oryginału: Visual Basic 2005 in a Nutshell
Format: B5, stron: 880
Przykłady na ftp: 7 kB
Visual Basic po raz pierwszy pojawił się na rynku w roku 1991 jako połączenie
oferowanego przez Microsoft języka QBasic z mechanizmem projektowania graficznego
interfejsu użytkownika. Od tej pory przeszedł sporą ewolucję, zyskując jednoczeSnie
ogromne grono zwolenników. W roku 2001 wprowadzono na rynek platformę
programistyczną .NET wraz z całkowicie zmienioną i odnowioną wersją Visual Basica
pod nazwą Visual Basic .NET. Visual Basic dla platformy .NET był językiem w pełni
obiektowym i oferował znacznie większe możliwoSci niż jego poprzednicy. Visual Basic
2005 to najnowsze wcielenie tego popularnego języka programowania.
Książka  Visual Basic 2005. Almanach to kompleksowe omówienie wszystkich
zagadnień związanych z programowaniem w tym języku. Czytając ją, poznasz genezę
platformy .NET, jej składniki i konstrukcję oraz słowa kluczowe języka Visual Basic.
Przeczytasz o programowaniu obiektowym, klasach platformy .NET, obsłudze zdarzeń
oraz typach uniwersalnych. Dalsza częSć książki to niezwykle przydatne każdemu
programiScie zestawienie dokumentacji wszystkich istotnych wyrażeń, procedur, funkcji
i obiektów Visual Basica zawierające omówienie składni i argumentów, wskazówki
dotyczące sposobu stosowania omawianego elementu języka, przykłady kodu oraz
opisy nieudokumentowanych zachowań.
W książce omówiono:
" Podstawowe wiadomoSci o platformie .NET
" Zasady programowania obiektowego
" Zmienne, typy danych i operatory
" Struktura programów w Visual Basic
" Klasy platformy .NET
" Typy uniwersalne
" Obsługa błędów i wyjątków
Wydawnictwo Helion
ul. KoSciuszki 1c " Leksykon elementów języka Visual Basic 2005
44-100 Gliwice
Zostań ekspertem w dziedzinie programowania w Visual Basicu
tel. 032 230 98 63
e-mail: helion@helion.pl
Spis treści
Przedmowa ................................................................................................................... 21
I Podstawy .................................................................................................29
1. Wprowadzenie .............................................................................................................. 31
Dlaczego Visual Basic .NET? 32
Czym jest Visual Basic .NET? 36
Co możemy zrobić w środowisku Visual Basic .NET? 42
Wersje języka Visual Basic .NET 43
2. Platforma .NET Framework: pojęcia ogólne ................................................................45
Środowisko uruchomieniowe wspólnego języka 45
Kod zarządzany 46
Przestrzenie nazw 47
Typy i obiekty 48
Podzespoły 49
Biblioteka klas platformy .NET (FCL) 51
Wdrażanie aplikacji 52
Platforma .NET i język Visual Basic 52
3. Wprowadzenie do programowania obiektowego .....................................................53
Reguły programowania obiektowego 53
Programowanie obiektowe w języku Visual Basic 58
4. Zmienne i typy danych .................................................................................................. 77
Typy danych 77
Zmienne 93
Stałe 97
Typy wyliczeniowe 98
Tablice 98
Kolekcje 99
Parametry i argumenty 100
3
5. Operatory .................................................................................................................... 105
Operatory arytmetyczne 105
Operatory konkatenacji 107
Operatory logiczne i bitowe 107
Operatory przypisania 112
Operatory porównania 114
Operatory obiektowe 115
Przeciążanie operatorów 117
Priorytety operatorów 119
6. Struktura programu .....................................................................................................121
Rodzaje aplikacji tworzonych w środowisku Visual Studio 121
Techniki odwołań do komponentów i klas 122
Punkty wejścia aplikacji 123
Zawartość pliku z kodem zródłowym 126
Struktura programu Visual Basica 127
7. Biblioteka klas platformy .NET ................................................................................... 135
Przestrzeń nazw System 136
Przestrzeń nazw System.Collections 142
Przestrzeń nazw System.Data 142
Przestrzeń nazw System.IO 143
Przestrzeń nazw System.Text.RegularExpressions 144
Przestrzeń nazw System.Windows.Forms 146
Pozostałe przestrzenie nazw 146
8. Delegacje i zdarzenia ..................................................................................................149
Delegacje 150
Zdarzenia i wiązanie zdarzeń 153
9. Atrybuty ...................................................................................................................... 159
Składnia i techniki stosowania 160
Definiowanie atrybutów niestandardowych 163
Korzystanie z atrybutów niestandardowych 166
10. Typy uniwersalne .........................................................................................................171
Czym są typy uniwersalne? 171
Parametry typów 172
Stosowanie wielu parametrów typów 173
Ograniczenia 173
Ograniczenia złożone 174
Uzyskiwanie dostępu do składowych parametrów typów 175
4 | Spis treści
Metody uniwersalne 177
Zagnieżdżone typy uniwersalne 177
Typy i składowe przeciążone 177
11. Obsługa błędów w Visual Basicu ............................................................................... 179
Wykrywanie i obsługa błędów 179
Obsługa błędów wykonywania 180
Obsługa błędów logiki 188
Stałe błędów 191
II Leksykon ................................................................................................ 193
12. Leksykon języka Visual Basic ...................................................................................... 195
#Const (dyrektywa) 197
#If...Then...#Else (dyrektywa) 198
#Region...#End Region (dyrektywa) 200
Abs (funkcja) 200
Acos (funkcja) 201
AddHandler (wyrażenie) 202
AddressOf (operator) 203
AppActivate (procedura) 203
Application (klasa) 205
Application.CompanyName (właściwość) 206
Application.DoEvents (metoda) 207
Application.ExecutablePath (właściwość) 208
Application.ProductName (właściwość) 209
Application.ProductVersion (właściwość) 209
Application.Run (metoda) 210
Array (klasa) 211
Array.BinarySearch (metoda) 212
Array.Copy (metoda) 214
Array.IndexOf (metoda) 215
Array.LastIndexOf (metoda) 216
Array.Reverse (metoda) 217
Array.Sort (metoda) 218
Asc i AscW (funkcje) 220
AssemblyVersion (atrybut) 220
Asin (funkcja) 221
Atan (funkcja) 222
Atan2 (funkcja) 223
AttributeUsage (atrybut) 224
Beep (procedura) 225
Spis treści | 5
Call (wyrażenie) 225
CallByName (funkcja) 226
CBool (funkcja) 228
CByte (funkcja) 228
CChar (funkcja) 229
CDate (funkcja) 230
CDbl (funkcja) 231
CDec (funkcja) 231
Ceiling (funkcja) 232
ChDir (procedura) 233
ChDrive (procedura) 234
Choose (funkcja) 235
Chr i ChrW (funkcje) 237
CInt (funkcja) 238
Class...End Class (wyrażenie) 239
Clipboard (klasa) 241
CLng (funkcja) 241
CLSCompliant (atrybut) 242
CObj (funkcja) 243
Collection (klasa) 244
Collection.Add (metoda) 245
Collection.Count (właściwość) 247
Collection.Item (właściwość) 248
Collection.Remove (metoda) 248
ColorDialog (klasa) 249
COMClass (atrybut) 251
Command (funkcja) 252
Const (wyrażenie) 254
Continue (wyrażenie) 255
Cos (funkcja) 256
Cosh (funkcja) 257
CreateObject (funkcja) 257
CSByte (funkcja) 259
CShort (funkcja) 260
CSng (funkcja) 261
CStr (funkcja) 262
CType (funkcja) 263
CUInt (funkcja) 265
CULng (funkcja) 266
CUShort (funkcja) 267
CurDir (funkcja) 268
Custom Event (wyrażenie) 268
6 | Spis treści
DateAdd (funkcja) 270
DateDiff (funkcja) 272
DatePart (funkcja) 274
DateSerial (funkcja) 276
DateString (właściwość) 277
DateValue (funkcja) 278
Day (funkcja) 278
DDB (funkcja) 279
Debug (klasa) 280
Debug.Assert (metoda) 282
Debug.Listeners (właściwość) 283
Debug.Write (metoda) 284
Debug.WriteIf (metoda) 284
Debug.WriteLine (metoda) 285
Debug.WriteLineIf (metoda) 286
Declare (wyrażenie) 287
DefaultMember (atrybut) 290
Delegate (wyrażenie) 292
DeleteSetting (procedura) 294
Dim (wyrażenie) 296
Dir (funkcja) 300
DirectCast (funkcja) 302
Directory (klasa) 303
Directory.CreateDirectory (metoda) 304
Directory.Delete (metoda) 305
Directory.Exists (metoda) 306
Directory.GetCreationTime (metoda) 307
Directory.GetDirectories (metoda) 307
Directory.GetDirectoryRoot (metoda) 309
Directory.GetFiles (metoda) 310
Directory.GetFileSystemEntries (metoda) 311
Directory.GetLogicalDrives (metoda) 312
Directory.GetParent (metoda) 313
Directory.Move (metoda) 314
Do...Loop (wyrażenie) 315
E (pole) 316
End (wyrażenie) 317
Enum (wyrażenie) 319
Environ (funkcja) 321
EOF (funkcja) 323
Erase (wyrażenie) 324
Erl (właściwość) 324
Spis treści | 7
Err (obiekt) 325
Err.Clear (metoda) 326
Err.Description (właściwość) 327
Err.GetException (metoda) 328
Err.HelpContext (właściwość) 328
Err.HelpFile (właściwość) 329
Err.LastDLLError (właściwość) 330
Err.Number (właściwość) 331
Err.Raise (metoda) 331
Err.Source (właściwość) 333
Error (wyrażenie) 333
ErrorToString (funkcja) 334
Event (wyrażenie) 334
Exception (klasa) 336
Exit (wyrażenie) 338
Exp (funkcja) 339
File (klasa) 339
File.Exists (metoda) 340
FileAttr (funkcja) 341
FileClose (procedura) 342
FileCopy (procedura) 343
FileDateTime (funkcja) 343
FileGet i FileGetObject (procedury) 344
FileLen (funkcja) 346
FileOpen (procedura) 347
FilePut i FilePutObject (procedury) 350
FileWidth (procedura) 351
Filter (funkcja) 352
Fix (funkcja) 353
Flags (atrybut) 354
Floor (funkcja) 354
FontDialog (klasa) 355
For...Next (wyrażenie) 357
For Each...Next (wyrażenie) 359
Format (funkcja) 360
FormatCurrency, FormatNumber i FormatPercent (funkcje) 364
FormatDateTime (funkcja) 365
FreeFile (funkcja) 366
Friend (słowo kluczowe) 367
Function (wyrażenie) 368
FV (funkcja) 372
GetAllSettings (funkcja) 373
8 | Spis treści
GetAttr (funkcja) 374
GetChar (funkcja) 375
GetObject (funkcja) 376
GetSetting (funkcja) 377
GetType (operator) 379
Global (słowo kluczowe) 379
GoTo (wyrażenie) 380
Guid (atrybut) 382
Handles (słowo kluczowe) 382
Hashtable (klasa) 384
Hashtable.Add (metoda) 385
Hashtable.ContainsKey (metoda) 386
Hashtable.ContainsValue (metoda) 386
Hashtable.CopyTo (metoda) 387
Hashtable.Item (właściwość) 388
Hashtable.Keys (właściwość) 389
Hashtable.Remove (metoda) 389
Hashtable.Values (właściwość) 390
Hex (funkcja) 390
Hour (funkcja) 391
IEEERemainder (funkcja) 391
If...Then...Else (wyrażenie) 392
IIf (funkcja) 394
Implements (słowo kluczowe) 395
Implements (wyrażenie) 396
Imports (wyrażenie) 398
Inherits (wyrażenie) 399
Input (procedura) 400
InputBox (funkcja) 402
InputString (funkcja) 403
InStr (funkcja) 404
InStrRev (funkcja) 405
Int (funkcja) 406
Interface...End Interface (wyrażenie) 407
IPmt (funkcja) 410
IRR (funkcja) 411
Is (operator) 412
IsArray (funkcja) 413
IsDate (funkcja) 414
IsDBNull (funkcja) 415
IsError (funkcja) 416
IsNot (operator) 417
Spis treści | 9
IsNothing (funkcja) 418
IsNumeric (funkcja) 419
IsReference (funkcja) 419
Join (funkcja) 420
Kill (procedura) 421
LBound (funkcja) 422
LCase (funkcja) 423
Left (funkcja) 423
Len (funkcja) 424
Like (operator) 425
LineInput (funkcja) 426
Loc (funkcja) 427
Lock (procedura) 428
LOF (funkcja) 430
Log (funkcja) 430
Log10 (funkcja) 432
LSet (funkcja) 432
LTrim (funkcja) 433
MarshalAs (atrybut) 434
Max (funkcja) 437
Me (słowo kluczowe) 438
Mid (funkcja) 439
Mid (wyrażenie) 440
Min (funkcja) 441
Minute (funkcja) 442
MIRR (funkcja) 442
MkDir (procedura) 443
Mod (operator) 444
Module...End Module (wyrażenie) 445
Month (funkcja) 446
MonthName (funkcja) 446
MsgBox (funkcja) 447
MTAThread (atrybut) 449
MyBase (słowo kluczowe) 450
MyClass (słowo kluczowe) 451
Namespace (wyrażenie) 453
New (słowo kluczowe) 453
Nothing (słowo kluczowe) 454
Now (właściwość) 455
NPer (funkcja) 455
NPV (funkcja) 457
Obsolete (atrybut) 458
10 | Spis treści
Oct (funkcja) 459
Of (słowo kluczowe) 459
On Error (wyrażenie) 460
OpenFileDialog (klasa) 462
Operator (wyrażenie) 464
Option Compare (wyrażenie) 466
Option Explicit (wyrażenie) 467
Option Strict (wyrażenie) 468
Out (atrybut) 469
ParamArray (atrybut) 471
Partial (słowo kluczowe) 471
Partition (funkcja) 472
PI (pole) 474
Pmt (funkcja) 475
Pow (funkcja) 476
PPmt (funkcja) 476
Print i PrintLine (procedury) 478
Private (słowo kluczowe) 479
Property (wyrażenie) 480
Protected (słowo kluczowe) 484
Public (słowo kluczowe) 486
PV (funkcja) 487
QBColor (funkcja) 488
Queue (klasa) 489
Queue.Contains (metoda) 490
Queue.CopyTo (metoda) 491
Queue.Dequeue (metoda) 492
Queue.Enqueue (metoda) 493
Queue.Peek (metoda) 493
Queue.ToArray (metoda) 494
RaiseEvent (wyrażenie) 494
Randomize (procedura) 496
Rate (funkcja) 497
ReDim (wyrażenie) 498
Rem (wyrażenie) 500
RemoveHandler (wyrażenie) 501
Rename (procedura) 502
Replace (funkcja) 503
Reset (procedura) 504
Resume (wyrażenie) 505
Return (wyrażenie) 506
RGB (funkcja) 507
Spis treści | 11
Right (funkcja) 508
RmDir (procedura) 509
Rnd (funkcja) 510
Round (funkcja) 511
RSet (funkcja) 512
RTrim (funkcja) 513
SaveFileDialog (klasa) 514
SaveSetting (procedura) 515
ScriptEngine (właściwość) 517
ScriptEngineBuildVersion (właściwość) 518
ScriptEngineMajorVersion (właściwość) 518
ScriptEngineMinorVersion (właściwość) 519
Second (funkcja) 519
Seek (funkcja) 520
Seek (procedura) 521
Select Case (wyrażenie) 522
Send, SendWait (metody) 524
SetAttr (procedura) 526
Shadows (słowo kluczowe) 528
Shared (słowo kluczowe) 528
Shell (funkcja) 529
Sign (funkcja) 531
Sin (funkcja) 532
Sinh (funkcja) 532
SLN (funkcja) 533
Space (funkcja) 534
SPC (funkcja) 534
Split (funkcja) 535
Sqrt (funkcja) 536
Stack (klasa) 537
Stack.Contains (metoda) 538
Stack.CopyTo (metoda) 539
Stack.Peek (metoda) 540
Stack.Pop (metoda) 541
Stack.Push (metoda) 541
Stack.ToArray (metoda) 542
STAThread (atrybut) 542
Static (wyrażenie) 543
Stop (wyrażenie) 543
Str (funkcja) 544
StrComp (funkcja) 545
StrConv (funkcja) 546
12 | Spis treści
StrDup (funkcja) 547
StrReverse (funkcja) 548
Structure...End Structure (wyrażenie) 549
Sub (wyrażenie) 551
Switch (funkcja) 554
SYD (funkcja) 555
SyncLock (wyrażenie) 556
SystemTypeName (funkcja) 557
TAB (funkcja) 557
Tan (funkcja) 558
Tanh (funkcja) 559
ThreadStatic (atrybut) 560
Throw (wyrażenie) 561
TimeOfDay (właściwość) 562
Timer (właściwość) 562
TimeSerial (funkcja) 563
TimeString (właściwość) 564
TimeValue (funkcja) 565
Today (właściwość) 566
Trim (funkcja) 566
Try...Catch...Finally (wyrażenie) 567
TryCast (funkcja) 569
TypeName (funkcja) 570
TypeOf (operator) 572
UBound (funkcja) 573
UCase (funkcja) 573
Unlock (procedura) 574
Using...End Using (wyrażenie) 575
Val (funkcja) 577
VarType (funkcja) 577
VBFixedArray (atrybut) 579
VBFixedString (atrybut) 580
VbTypeName (funkcja) 581
WebMethod (atrybut) 582
WebService (atrybut) 583
Weekday (funkcja) 584
WeekdayName (funkcja) 585
While...End While (wyrażenie) 586
With...End With (wyrażenie) 587
WithEvents (słowo kluczowe) 588
Write i WriteLine (procedury) 588
Year (funkcja) 590
Spis treści | 13
13. Leksykon przestrzeni nazw My .................................................................................. 591
AllUsersApplicationData (właściwość) 592
AltKeyDown (właściwość) 593
Application (obiekt) 594
ApplicationContext (właściwość) 595
AssemblyName (właściwość) 596
Audio (obiekt) 597
AvailablePhysicalMemory (właściwość) 597
AvailableVirtualMemory (właściwość) 598
ButtonsSwapped (właściwość) 599
CapsLock (właściwość) 599
ChangeCulture (metoda) 600
ChangeUICulture (metoda) 601
ClassesRoot (właściwość) 602
Clear (metoda) 603
Clipboard (obiekt) 603
Clock (obiekt) 605
Close (metoda) 605
CombinePath (metoda) 606
CommandLineArgs (właściwość) 607
CommentTokens (właściwość) 608
CompanyName (właściwość) 609
Computer (obiekt) 610
ContainsAudio (metoda) 611
ContainsData (metoda) 611
ContainsFileDropList (metoda) 612
ContainsImage (metoda) 613
ContainsText (metoda) 613
CopyDirectory (metoda) 614
CopyFile (metoda) 616
Copyright (właściwość) 618
CreateDirectory (metoda) 619
CtrlKeyDown (właściwość) 620
Culture (właściwość) 620
CurrentConfig (właściwość) 621
CurrentDirectory (właściwość) 622
CurrentPrincipal (właściwość) 623
CurrentUser (właściwość) 624
CurrentUserApplicationData (właściwość) 625
DefaultFileLogWriter (właściwość) 626
DeleteDirectory (metoda) 627
DeleteFile (metoda) 629
14 | Spis treści
Delimiters (właściwość) 630
Deployment (właściwość) 632
Description (właściwość) 633
Desktop (właściwość) 634
DirectoryExists (metoda) 634
DirectoryPath (właściwość) 635
DoEvents (metoda) 636
DownloadFile (metoda) 637
Drives (właściwość) 638
DynData (właściwość) 639
EndOfData (właściwość) 640
ErrorLine (właściwość) 641
ErrorLineNumber (właściwość) 642
FieldWidths (właściwość) 643
FileExists (metoda) 644
FileSystem (obiekt) 645
FindInFiles (metoda) 646
Forms (obiekt) 648
GetAudioStream (metoda) 649
GetData (metoda) 650
GetDataObject (metoda) 651
GetDirectories (metoda) 652
GetDirectoryInfo (metoda) 653
GetDriveInfo (metoda) 655
GetEnvironmentVariable (metoda) 656
GetFileDropList (metoda) 657
GetFileInfo (metoda) 658
GetFiles (metoda) 660
GetImage (metoda) 661
GetName (metoda) 662
GetParentPath (metoda) 663
GetTempFileName (metoda) 664
GetText (metoda) 665
GetValue (metoda) 666
GmtTime (właściwość) 667
HasFieldsEnclosedInQuotes (właściwość) 668
Info (obiekt składowy obiektu My.Application) 669
Info (obiekt składowy obiektu My.Computer) 670
InitializeWithWindowsUser (metoda) 670
InstalledUICulture (właściwość) 671
IsAuthenticated (właściwość) 672
IsAvailable (właściwość) 672
Spis treści | 15
IsInRole (metoda) 673
IsNetworkDeployed (właściwość) 674
Keyboard (obiekt) 675
LineNumber (właściwość) 676
LoadedAssemblies (właściwość) 677
LocalMachine (właściwość) 678
LocalTime (właściwość) 679
Log (obiekt składowy przestrzeni nazw My) 680
Log (obiekt składowy obiektu My.Application) 680
MinimumSplashScreenDisplayTime (właściwość) 681
Mouse (obiekt) 682
MoveDirectory (metoda) 683
MoveFile (metoda) 684
My (przestrzeń nazw) 686
MyDocuments (właściwość) 687
MyMusic (właściwość) 688
MyPictures (właściwość) 689
Name (właściwość składowa obiektu My.Computer) 690
Name (właściwość składowa obiektu My.User) 690
Network (obiekt) 691
NetworkAvailabilityChanged (zdarzenie składowe obiektu My.Application) 692
NetworkAvailabilityChanged
(zdarzenie składowe obiektu My.Computer.Network) 693
NumLock (właściwość) 694
OpenForms (właściwość) 695
OpenSerialPort (metoda) 696
OpenTextFieldParser (metoda) 698
OpenTextFileReader (metoda) 699
OpenTextFileWriter (metoda) 701
OSFullName (właściwość) 702
OSPlatform (właściwość) 703
OSVersion (właściwość) 704
PeekChars (metoda) 705
PerformanceData (właściwość) 706
Ping (metoda) 706
Play (metoda) 707
PlaySystemSound (metoda) 709
Ports (obiekt) 710
ProductName (właściwość) 711
ProgramFiles (właściwość) 711
Programs (właściwość) 712
ReadAllBytes (metoda) 713
16 | Spis treści
ReadAllText (metoda) 714
ReadFields (metoda) 715
ReadLine (metoda) 716
ReadToEnd (metoda) 717
Registry (obiekt) 718
RenameDirectory (metoda) 719
RenameFile (metoda) 720
Request (obiekt) 721
Resources (obiekt) 722
Response (obiekt) 723
Run (metoda) 724
SaveMySettingsOnExit (właściwość) 725
Screen (właściwość) 726
ScrollLock (właściwość) 727
SendKeys (metoda) 727
SerialPortNames (właściwość) 730
SetAudio (metoda) 731
SetData (metoda) 732
SetDataObject (metoda) 733
SetDelimiters (metoda) 734
SetFieldWidths (metoda) 735
SetFileDropList (metoda) 736
SetImage (metoda) 737
SetText (metoda) 738
Settings (obiekt) 739
SetValue (metoda) 741
ShiftKeyDown (właściwość) 743
Shutdown (zdarzenie) 743
SpecialDirectories (obiekt) 744
SplashScreen (właściwość) 745
StackTrace (właściwość) 746
Startup (zdarzenie) 748
StartupNextInstance (zdarzenie) 749
Stop (metoda) 750
Temp (właściwość) 751
TextFieldParser (obiekt) 752
TextFieldType (właściwość) 753
TickCount (właściwość) 754
Title (właściwość) 755
TotalPhysicalMemory (właściwość) 756
TotalVirtualMemory (właściwość) 757
TraceSource (właściwość) 757
Spis treści | 17
Trademark (właściwość) 759
TrimWhiteSpace (właściwość) 759
UICulture (właściwość) 760
UnhandledException (zdarzenie) 761
UploadFile (metoda) 762
User (obiekt) 764
Users (właściwość) 765
Version (właściwość) 766
WebServices (obiekt) 767
WheelExists (właściwość) 768
WheelScrollLines (właściwość) 769
WorkingSet (właściwość) 770
WriteAllBytes (metoda) 770
WriteAllText (metoda) 771
WriteEntry (metoda) 772
WriteException (metoda) 774
III Dodatki .................................................................................................. 777
A Elementy języka Visual Basic według kategorii ........................................................779
Obsługa tablic 780
Schowek 780
Obiekty kolekcji 781
Popularne okna dialogowe 782
Kompilacja warunkowa 782
Konwersja 782
Data i godzina 783
Diagnostyka 784
Deklaracja 784
Obsługa błędów 785
System plików 786
Operacje finansowe 787
Informacja 787
Wejście-wyjście 788
Zintegrowane środowisko programowania 789
Interakcja 789
Matematyka 790
Struktura programu i przepływ sterowania 791
Programowanie obiektowe i różne konstrukcje programowe 791
Rejestr 793
Operacje na łańcuchach 793
18 | Spis treści
B Hierarchia przestrzeni nazw ......................................................................................795
Hierarchia przestrzeni nazw My 795
Hierarchia przestrzeni nazw System 801
C Stałe i typy wyliczeniowe .......................................................................................... 805
Stałe wbudowane Visual Basica 805
Klasa ControlChars 808
Typy wyliczeniowe Visual Basica 809
D Co dodano, a co zmieniono w Visual Basicu .NET 2002? ..........................................815
Zmiany językowe wprowadzone w Visual Basicu .NET 2002 815
Zmiany dotyczące konstrukcji programistycznych 824
Przestarzałe konstrukcje programistyczne 826
Ustrukturalizowana obsługa wyjątków 827
Zmiany w technikach programowania obiektowego 827
E Co dodano, a co zmieniono w Visual Basicu .NET 2003? ..........................................831
Zmiany językowe wprowadzone w Visual Basicu .NET 2003 831
F Co dodano, a co zmieniono w Visual Basicu 2005? ................................................. 833
Rozszerzenia istniejącej funkcjonalności 834
Przestrzeń nazw My 837
Pozostałe nowości 838
G Elementy Visual Basica 6, które nie są już obsługiwane ..........................................841
H Kompilator Visual Basica obsługiwany z poziomu wiersza poleceń .......................847
Podstawy kompilatora Visual Basica 847
Przełączniki wiersza poleceń 848
Stosowanie pliku odpowiedzi 853
Stałe kompilacji warunkowej 854
Skorowidz ....................................................................................................................857
Spis treści | 19
ROZDZIAA 4.
Zmienne i typy danych
Mechanizmy odpowiedzialne za przetwarzanie danych są sercem wszystkich aplikacji pro-
gramowych. Moglibyśmy oczywiście przetwarzać dane tak jak robi to procesor komputera,
czyli bit po bicie, jednak praca nad odpowiednimi algorytmami szybko by nas znużyła 
właśnie dlatego takie języki jak Visual Basic oferują rozmaite typy danych oraz implementacje
narzędzi zarządzających danymi (z których każdy bazuje na jakimś podzbiorze możliwych
wartości danych). W niniejszym rozdziale zajmiemy się typami danych, sposobami zarzą-
dzania danymi przez te typy oraz technikami ich przetwarzania w języku Visual Basic i plat-
formie .NET.
Pojęcie  typ danych nie jest tożsame z bardziej ogólnym terminem  typ wykorzystywanym
w rozmaitych aspektach w tej i innych publikacjach poświęconych technologii .NET. Cała
koncepcja platformy .NET bazuje na pojęciu typu, czyli podstawowej konstrukcji danych
obejmującej klasy, struktury, delegacje i inne wysokopoziomowe elementy wykorzystywane
w procesie konstruowania aplikacji oraz podczas przekazywania danych pomiędzy progra-
mami. Typy danych dostępne w platformie .NET bazują właśnie na tych ogólnie rozumianych
typach (podobnie zresztą jak klasy budowane przez samych programistów). Typy danych
oferują stosunkowo niewielki, ale bardzo istotny zbiór narzędzi przetwarzania danych pogru-
powanych według podzbiorów możliwych wartości (zarządzanych w ramach poszczególnych
typów danych).
Typy danych
Środowisko uruchomieniowe wspólnego języka platformy .NET (CLR) obejmuje między inny-
mi wspólny system typów (CTS), który definiuje typy danych obsługiwane właśnie przez śro-
dowisko CLR. Wszystkie języki programowania przystosowane do współpracy z platformą
.NET muszą implementować przynajmniej podzbiory typów danych środowiska CLR (część
języków implementuje wszystkie, np. Visual Basic począwszy od wydania z 2005 roku).
W technologii .NET typy danych mają postać specjalnych klas i struktur, których egzemplarze
reprezentują wartości danych należące do ograniczonych przedziałów (właściwych dla poszcze-
gólnych typów). Przykładowo, typ danych Byte oferuje możliwość reprezentowania i zarzą-
dzania 8-bitowymi wartościami całkowitoliczbowymi bez znaku, czyli liczbami z przedziału
od 0 do 255. Egzemplarze tego typu nie mogą zawierać wartości spoza tego przedziału (pod-
zbioru), ale przynajmniej z tym konkretnym podzbiorem radzą sobie znakomicie. Platforma
.NET oferuje typy danych dla tych podzbiorów wartości, które są najczęściej wykorzystywane
77
przez programistów podczas wytwarzania aplikacji. Za pomocą tych typów można reprezen-
tować niemal dowolne kombinacje danych. Jeśli predefiniowane typy danych platformy .NET
nie odpowiadają naszym potrzebom, możemy te typy wykorzystać w roli bloków składających
się na naszą własną klasę zarządzającą danymi.
Platforma .NET Framework implementuje blisko dwadzieścia podstawowych typów danych,
z których większość zaprojektowano z myślą o przetwarzaniu liczb całkowitych i zmienno-
przecinkowych. Rdzenne typy danych Visual Basica (znane jeszcze sprzed wprowadzenia plat-
formy .NET) stanowią tylko opakowania dla wspomnianych typów podstawowych systemu
CTS. Przykładowo, stosowany w Visual Basicu typ danych Integer jest opakowaniem struktury
System.Int32. Jedną z wartości struktury Int32 jest stała MaxValue reprezentująca mak-
symalną wartość numeryczną, którą można składować w tym typie danych. Oznacza to, że
choć składowa MaxValue nie jest oficjalną częścią Visual Basica, pełna zależność typu danych
Integer od wspomnianego typu podstawowego Int32 systemu CTS powoduje, że poniższa
para wyrażeń zostanie prawidłowo skompilowana i wykonana:
Dim usesInt32 As Integer
MsgBox(usesInt32.MaxValue) ' Wyświetla 2147483647
Przed wydaniem wersji 2005 tylko niektóre spośród podstawowych typów danych platformy
.NET były implementowane w Visual Basicu. Nawet mimo braku odpowiednich opakowań
Visual Basica, wcześniejsze wydania tego języka (oczywiście już w ramach platformy .NET)
udostępniały  nieopakowane typy danych systemu CTS. Ponieważ podstawowe typy danych
platformy .NET mają postać klas i struktur, można z nich korzystać w Visual Basicu dokład-
nie tak jak z innych klas czy struktur.
Typy wartościowe i referencyjne
Typy danych w języku Visual Basic można podzielić pomiędzy dwie dość ogólne kategorie:
typy wartościowe (ang. data types) oraz typy referencyjne (ang. reference types). Typy wartościo-
we różnią się od typów referencyjnych przede wszystkim sposobem składowania w pamięci.
Pamięć przydzielana zmiennej typu wartościowego zawiera właściwą wartość tej zmiennej.
Przykładowo, w czasie wykonywania poniższego wyrażenia:
Dim simpleValue As Integer = 5
zostanie zarezerwowane miejsce w pamięci potrzebne do składowania przypisywanej warto-
ści 5. Inaczej jest w przypadku typów referencyjnych, gdzie pod adresami pamięci przydzielo-
nymi tym zmiennym są składowane adresy innych bloków pamięci, w których znajdują się wła-
ściwe dane. Mechanizm stosowany w typach referencyjnych przypomina trochę usługę
pocztową polegającą na przesyłaniu pod inny adres listów oryginalnie kierowanych do okre-
ślonego odbiorcy. Przykładowo, dla poniższej deklaracji typu referencyjnego:
Dim somewhereElse As New MyCustomClass
kompilator Visual Basica utworzy w pamięci egzemplarz klasy MyCustomClass, po czym przy-
pisze zmiennej somewhereElse rzeczywisty adres w pamięci tego egzemplarza. Programistom,
którzy mają doświadczenie w pracy ze wskaznikami oferowanymi przez takie języki jak C++,
zrozumienie mechanizmu stosowanego w Visual Basicu nie powinno sprawić najmniejszych
problemów, ponieważ oba rozwiązania są bardzo podobne.
Najkrócej mówiąc, zmienne typów wartościowych zawierają dane, natomiast zmienne typów
referencyjnych tylko na te dane wskazują.
78 | Rozdział 4. Zmienne i typy danych
Różnice pomiędzy typami wartościowymi a typami referencyjnymi powodują szereg konse-
kwencji  jedną z najważniejszych jest sposób wykonywania popularnych operacji przypi-
sania. Przeanalizujmy poniższą klasę, która zawiera tylko jedno pole składowe:
Public Class SimpleClass
Public Age As Short
End Class
oraz strukturę będącą odpowiednikiem tej klasy:
Structure SimpleStruct
Public Age As Short
End Structure
W przeciwieństwie do struktur, które są typami wartościowymi, klasy są typami referencyj-
nymi. Poniższy kod ilustruje podstawową różnicę w korzystaniu z tej pary podobnych, ale
mimo wszystko różnych typów:
' ----- Deklaruje cztery zmienne, po dwie dla każdego z typów.
Dim refType1 As SimpleClass
Dim refType2 As SimpleClass
Dim valType1 As SimpleStruct
Dim valType2 As SimpleStruct
' ----- W pierwszej kolejności skoncentrujemy się na typach referencyjnych.
' Przypisanie refType2 = refType1 spowoduje, że obie zmienne refType2
' będą wskazywały na ten sam adres w pamięci. Od tej pory zmiany
' składowych zmiennej refType1 będą miały wpływ na składowe zmiennej
' refType2 i odwrotnie. Obie zmienne współdzielą ten sam egzemplarz.
refType1 = New SimpleClass
refType1.Age = 20
refType2 = refType1
refType2.Age = 30
Debug.WriteLine(refType1.Age) ' --> Wyświetla 30
Debug.WriteLine(refType2.Age) ' --> Wyświetla 30
' ----- Przyjrzyjmy się teraz typom wartościowym. Przypisanie valType2 = valType1
' powoduje wykonanie kopii składowych zmiennej valType1. Od tej pory zmiany
' składowych jednej z tych zmiennych nie będą miały wpływu na wartości
' składowych drugiej zmiennej.
valType1 = New SimpleStruct
valType1.Age = 20
valType2 = valType1
valType2.Age = 30
Debug.Writeline(valType1.Age) ' --> Wyświetla 20
Debug.Writeline(valType2.Age) ' --> Wyświetla 30
W pewnym sensie obie operacje przypisania jednej zmiennej drugiej zmiennej realizują to samo
zadanie  kopiują wartość reprezentowaną przez zmienną użytą po prawej stronie do zmien-
nej na lewo od operatora przypisania. Ponieważ jednak rzeczywistą wartością typu referen-
cyjnego (w tym przypadku zmiennej refType1) jest adres w pamięci, właśnie adres został skopio-
wany do zmiennej refType2. Ponieważ obie zmienne wskazują na ten sam obszar w pamięci
(miejsce przechowywania składowych obiektu klasy SimpleClass), w praktyce zmienne ref-
Type1 i refType2 współdzielą jeden zbiór składowych.
Przypisanie jednej zmiennej typu wartościowego (valType1) innej zmiennej typu wartościowego
(valType2) także polega na skopiowaniu wartości zmiennej użytej na prawo od operatora przy-
pisania do zmiennej użytej z lewej strony tego operatora. Różnica polega na tym, że zmienna
valType1 zawiera rzeczywiste składowe (nie adres miejsca ich przechowywania w pamięci).
Oznacza to, że zmienna docelowa valType2 zawiera odrębną kopię tych składowych (w tym
przypadku jedynej składowej Age).
Typy danych | 79
Wyzerowanie zmiennej typu referencyjnego wymaga przypisania jej wartości Nothing. Typy
wartościowe zawsze reprezentują jakieś wartości (nawet jeśli są to same zera), zatem w ich
przypadku przypisywanie  wartości Nothing nie jest możliwe.
Wszystkie podstawowe typy danych Visual Basica, które zarządzają wartościami numerycz-
nymi (czyli np. Integer oraz Double), są typami wartościowymi. Typ danych String jest co
prawda przykładem typu referencyjnego, jednak z perspektywy programisty funkcjonuje
dokładnie tak jak typy wartościowe. Za każdym razem gdy przypisujemy jedną zmienną
łańcuchową innej, wbrew pozorom w łańcuchu docelowym nie jest zapisywana referencja do
pierwszego łańcucha (jak w przypadku innych typów referencyjnych). Wynika to z faktu, że
stosowana w Visual Basicu implementacja typu danych String każdorazowo (zarówno pod-
czas przypisywania, jak i modyfikowania) tworzy zupełnie nowy egzemplarz oryginalnego
łańcucha.
Podstawowe typy danych Visual Basica: przegląd
Język programowania Visual Basic począwszy od wersji 2005 implementuje wszystkie pod-
stawowe typy danych platformy .NET Framework (a konkretnie wspólnego systemu typów,
CTS). Okazuje się, że podstawowe typy danych oferują bardzo szeroki zakres funkcjonalności
i pozwalają zarządzać niemal wszystkimi kategoriami danych. Typy danych należące do sys-
temu CTS można podzielić na pięć grup (według rodzaju zarządzanych danych):
Dane logiczne
Pojedynczy typ danych, który obejmuje tylko jeden bit reprezentujący prawdę lub fałsz
(odpowiednio True lub False).
Dane znakowe
Visual Basic oferuje typy danych zarządzające zarówno pojedynczymi znakami, jak i dłu-
gimi łańcuchami znaków.
Dane czasu i daty
Pojedynczy typ danych zarządzający wartościami reprezentującymi zarówno datę, jak
i godzinę.
Dane zmiennoprzecinkowe
Rozmaite typy danych reprezentujące wartości zmiennoprzecinkowe  każdy z tych typów
zarządza ograniczonym podzbiorem liczb wymiernych. Niektóre z tych typów oferują więk-
szą precyzję matematyczną od pozostałych.
Dane całkowitoliczbowe
Ta kategoria obejmuje wiele całkowitoliczbowych typów danych, które umożliwiają skła-
dowanie liczb całkowitych należących do właściwego (zależnego od typu) przedziału (od
wartości minimalnej do maksymalnej). Część typów danych całkowitoliczbowych obsłu-
guje wartości ujemne.
W dalszej części tego punktu przedstawimy definicje i stosowne komentarze do każdej z wy-
mienionych powyżej kategorii typów danych obsługiwanych przez Visual Basic.
Typ danych Boolean
Podstawowe fakty
Podstawowy typ .NET: System.Boolean
Implementacja: Typ wartościowy (struktura)
80 | Rozdział 4. Zmienne i typy danych
Ilość zajmowanej pamięci: 2 bajty
Zakres wartości: True lub False
Typ danych Boolean może reprezentować tylko dwie wartości (True lub False). W języku
Visual Basic mamy do dyspozycji słowa kluczowe True i False, które są stosowane w roli warto-
ści zmiennych typu Boolean. Zmiennym tego typu można też przypisywać wyniki dowol-
nych operacji logicznych.
Kiedy wartość numeryczna jest konwertowana na wartość typu Boolean, wszystkie wartości
różne od zera są przekształcane w wartość True, a jedyną wartością tłumaczoną na False jest
zero. W razie konwersji w drugą stronę wartość False jest zamieniana na zero, natomiast
wartość True jest zamieniana na liczbę  1. (Ta część funkcjonalności odróżnia Visual Basica
od pozostałych języków platformy .NET, które konwertują wartość True na 1. W Visual Basicu
zastosowano w tej roli liczbę  1, aby zapewnić zgodność wstecz. W razie współdzielenia danych
logicznych pomiędzy komponentami napisanymi w różnych językach platformy .NET, środo-
wisko uruchomieniowe .NET Framework i tak automatycznie przekształci te wartości w spo-
sób gwarantujący pełną zgodność).
Typ danych Byte
Podstawowe fakty
Podstawowy typ .NET: System.Byte
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 1 bajt
Zakres wartości: Od 0 do 255 (bez znaku)
Typ danych Byte jest najmniejszym dostępnym w Visual Basicu typem całkowitoliczbowym
bez znaku. Mimo bardzo niewielkiego przedziału obsługiwanych wartości zmienne typu Byte
doskonale zdają egzamin podczas pracy z nieprzetworzonymi danymi binarnymi.
Typ danych Char
Podstawowe fakty
Podstawowy typ .NET: System.Char
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 2 bajty
Zakres wartości: Kody znaku z przedziału od 0 do 65535 (bez znaku)
Typ danych Char reprezentuje pojedynczy, 16-bitowy znak Unicode. Wszystkie znaki w plat-
formie .NET są reprezentowane właśnie za pomocą kodów 16-bitowych, co oczywiście wy-
starczy do obsługi języków wymagających stosowania 2-bajtowego zbioru znaków (ang. Double-
-Byte Character Set  DBCS), czyli np. języka japońskiego. Wersje Visual Basica sprzed wprowa-
dzenia platformy .NET nie zawierały żadnego odpowiednika typu danych char.
Stosując stałe wartości typu Char, należy do nich dołączać (za cudzysłowem zamykającym)
pojedynczą literę c:
Dim singleLetter As Char = "A"c
Typy danych | 81
Zmienna łańcuchowa (typu String), która zawiera tylko jeden znak, nie jest tożsama ze
zmienną typu Char zawierającą ten sam znak. Ponieważ są to dwa zupełnie różne typy,
ewentualne przenoszenie danych pomiędzy zmiennymi tych typów wymaga stosownej kon-
wersji (jeśli włączono opcję Option Strict).
Typ danych DateTime
Podstawowe fakty
Podstawowy typ .NET: System.DateTime
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 8 bajtów
Zakres wartości: Od 1 stycznia 1 roku n.e. do 31 grudnia 9999 roku n.e. (w kalendarzu
gregoriańskim)
Wartości reprezentujące daty i czas mają postać 64-bitowych, długich liczb całkowitych zgod-
nych ze standardem IEEE. Za pomocą tak długich liczb można reprezentować daty z prze-
działu od 1 stycznia 1 roku n.e. do 31 grudnia 9999 roku n.e. oraz godziny z przedziału od
0:00:00 do 23:59:59. Odpowiednie wartości reprezentują liczbę  tyknięć , które upłynęły od 1 sty-
cznia 1 roku n.e. Każde takie  tyknięcie odpowiada 100 nanosekundom.
Stałe daty należy umieszczać pomiędzy dwoma znakami krzyżyków (#):
Dim independenceDay As Date = #7/4/1776#
Typ danych Decimal
Podstawowe fakty
Podstawowy typ .NET: System.Decimal
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 12 bajtów
Zakres wartości: +/ 79 228 162 514 264 337 593 543 950 335 bez części dziesiętnej;
+/ 7.9228162514264337593543950335 z 28 miejscami po przecinku; najmniejsza wartość
różna od zera wynosi +/ 0.0000000000000000000000000001
Wartości typu danych Decimal są składowane w formie 96-bitowych liczb całkowitych ze
znakiem; reprezentacja tych wartości dodatkowo obejmuje wewnętrzny (obsługiwany i sto-
sowany w pełni automatycznie) współczynnik skali z przedziału od 0 do 28. Takie rozwią-
zanie zapewnia wysoki poziom precyzji matematycznej w przypadku liczb należących do
odpowiedniego przedziału wartości (typ Decimal szczególnie dobrze sprawdza się w przypadku
danych walutowych).
Na końcu wartości stałych typu Decimal należy umieszczać albo pojedynczą literę D, albo
znak @:
Dim startingValue As Decimal = 123.45D
Dim endingValue As Decimal = 543.21@
Znak @ można stosować także do oznaczania deklarowanych zmiennych jako egzemplarzy
typu Decimal:
Dim startingValue@ = 123.45D
82 | Rozdział 4. Zmienne i typy danych
Składowe typu danych Decimal nazwane MaxValue i MinValue reprezentują granice obsłu-
giwanego przedziału wartości (odpowiednio wartość maksymalną i minimalną).
W implementacjach Visual Basica sprzed wprowadzenia technologii .NET typ danych Deci-
mal w praktyce nie stanowił odrębnego, autonomicznego typu danych  był podtypem typu
danych Variant. Dopiero w wersjach kwalifikujących Visual Basic do rodziny języków plat-
formy .NET zaimplementowano typ Decimal w formie pełnowartościowego typu danych.
Typ danych Double
Podstawowe fakty
Podstawowy typ .NET: System.Double
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 8 bajtów
Zakres wartości: Od  1.79769313486231E+308 do  4.94065645841247E-324 w przypadku
liczb ujemnych; od 4.94065645841247E 324 do 1.79769313486232E+308 w przypadku
liczb dodatnich
Wartości typu Double są zgodne ze standardem IEEE dla 64-bitowych (8-bajtowych) liczb
zmiennoprzecinkowych podwójnej precyzji ze znakiem. Mimo ogromnego przedziału obsłu-
giwanych wartości, stosując typ danych Double musimy się liczyć z utratą precyzji w pew-
nych obliczeniach matematycznych.
Stałe egzemplarze typu danych Double należy oznaczać wielką literą R lub znakiem krzyżyka
(#) dołączanym bezpośrednio po wartościach numerycznych:
Dim startingValue As Double = 123.45R
Dim endingValue As Double = 543.21#
Znak krzyżyka (#) można stosować także do oznaczania deklarowanych zmiennych jako egzem-
plarzy typu Double:
Dim startingValue# = 123.45R
Typ danych Int32 (Integer)
Podstawowe fakty
Podstawowy typ .NET: System.Int32
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 4 bajty
Zakres wartości: Od  2 147 483 648 do 2 147 483 647
Typ danych Integer umożliwia reprezentowanie 32-bitowych liczb całkowitych ze znakiem.
Właśnie tyle wynosi rdzenna długość słowa w procesorach 32-bitowych, zatem stosowanie
tego rodzaju wartości powinno się przekładać na nieznacznie wyższą wydajność w porówna-
niu z pozostałymi typami całkowitoliczbowymi.
W wersjach Visual Basica sprzed wprowadzenia platformy .NET zmienne i stałe typu Integer
zajmowały tylko 16 bitów i  tym samym  mogły służyć do reprezentowania liczb całko-
witych z dużo mniejszego przedziału. W wersjach języka Visual Basic wchodzących w skład
rodziny języków platformy .NET dodatkowo mamy do dyspozycji typ danych Short, czyli
16-bitowy typ całkowitoliczbowy ze znakiem.
Typy danych | 83
Stałe egzemplarze typu Integer można opcjonalnie oznaczać wielką literą I lub znakiem
procenta (%) dołączanym na końcu wartości numerycznej:
Dim startingValue As Integer = 123I
Dim endingValue As Integer = 543%
Znak procenta (%) można stosować także do oznaczania deklarowanych zmiennych jako egzem-
plarzy typu Integer:
Dim startingValue% = 123I
Typ danych Int64 (Long)
Podstawowe fakty
Podstawowy typ .NET: System.Int64
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 8 bajtów
Zakres wartości: Od  9 223 372 036 854 775 808 do 9 223 372 036 854 775 807
Long jest 64-bitowym typem danych całkowitoliczbowych ze znakiem. W wersjach Visual Basica
sprzed wprowadzenia platformy .NET zmienne i stałe typu Long zajmowały tylko 32 bity i tym
samym mogły służyć do reprezentowania liczb całkowitych z dużo mniejszego przedziału.
W wersjach języka Visual Basic wchodzących w skład rodziny języków platformy .NET mamy
do dyspozycji typ danych Integer, czyli 32-bitowy typ całkowitoliczbowy ze znakiem.
Stałe egzemplarze typu Long należy oznaczać wielką literą L lub znakiem & dołączanym na
końcu wartości numerycznej:
Dim startingValue As Long = 123L
Dim endingValue As Long = 543&
Znak & można stosować także do oznaczania deklarowanych zmiennych jako egzemplarzy typu
Long:
Dim startingValue& = 123L
Stosując znak & do oznaczania stałych typu Long, w żadnym razie nie należy pozostawiać
spacji pomiędzy wartością całkowitoliczbową a tym znakiem, ponieważ znak & dodatkowo
pełni w Visual Basicu funkcję operatora konkatenacji łańcuchów.
Typ danych Object
Podstawowe fakty
Podstawowy typ .NET: System.Object
Implementacja: Typ referencyjny (klasa)
Ilość zajmowanej pamięci: 4 bajty
Zakres wartości: Zmienna typu Object może reprezentować dowolny typ
Object jest uniwersalnym typem danych, co oznacza, że zmienna typu Object może się odwo-
ływać do danych (wskazywać na dane) dowolnego innego typu danych. Przykładowo, egzem-
plarz klasy Object może wskazywać na wartość typu Long, wartość typu String lub egzem-
plarz dowolnej innej klasy.
Dim amazingVariable As Object
amazingVariable = 123L
amazingVariable = "Czyż to nie wspaniałe?"
amazingVariable = New MyCustomClass
84 | Rozdział 4. Zmienne i typy danych
Warto pamiętać, że ze stosowaniem zmiennych typu Object wiążą się pewne koszty w wy-
miarze wydajności oprogramowania. Visual Basic nie może związać właściwych składowych
reprezentujących dane ze zmienną typu Object w czasie kompilacji, co oznacza, że odpo-
wiednie łączenie musi nastąpić w czasie wykonywania programu  to z kolei powoduje, że
przetwarzanie metod związanych z tym obiektem wymaga większej ilości kodu. Opisywana
technika bywa nazywana póznym wiązaniem (ang. late binding). Deklarowanie obiektów z wła-
ściwymi (konkretnymi) typami danych skutkuje wczesnym wiązaniem (ang. early binding),
ponieważ za zarządzanie związkami wszystkich składowych odpowiada kompilator. Przy-
kładowo, poniższy fragment kodu:
Dim lateBound As Object
. . .
lateBound = New MyCustomClass
lateBound.SomeMethod( )
wymusi na aplikacji dopasowanie zmiennej lateBound do składowej SomeMethod klasy MyCu-
stomClass w czasie wykonywania. Przedstawione rozwiązanie jest więc dużo mniej wydajne
od mechanizmu zastosowanego poniżej:
Dim earlyBound As MyCustomClass
. . .
earlyBound = New MyCustomClass
earlyBound.SomeMethod( )
W wersjach języka Visual Basic sprzed wprowadzenia technologii .NET programista miał do
dyspozycji funkcję VarType, która identyfikowała konkretny podtyp wartości typu Variant.
Okazuje się, że funkcja VarType istnieje także w kolejnych wersjach Visual Basica .NET i służy
do identyfikacji faktycznych typów zmiennych lub wartości. Klasa System.Object (i klasy
potomne, czyli wszystkie klasy w technologii .NET) dodatkowo udostępnia metodę GetType,
która zwraca informację o prawdziwym typie danego obiektu. Chociaż wymienione rozwią-
zania można stosować dla dowolnych typów danych, ich przydatność jest szczególnie widoczna
właśnie w przypadku obiektów typu Object.
Typ danych SByte
Podstawowe fakty
Podstawowy typ .NET: System.SByte
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 1 bajt
Zakres wartości: Od  128 do 127
Nowość w wersji 2005. SByte jest najmniejszym typem danych całkowitoliczbowych ze zna-
kiem obsługiwanym przez Visual Basica. Typ SByte jest więc odpowiednikiem opisanego wcze-
śniej typu danych Byte (bez znaku) obejmującym znak.
SByte jest jednym z czterech typów danych dodanych do języka programowania Visual Basic
w wydaniu z roku 2005, które nie są wymienione w minimalnej specyfikacji wspólnego języka
(CLS). W związku z tym, komponenty i aplikacje zbudowane według zaleceń tego minimal-
nego standardu mogą nie być kompatybilne z aplikacjami wykorzystującymi ten typ danych.
Typy danych | 85
Typ danych Int16 (Short)
Podstawowe fakty
Podstawowy typ .NET: System.Int16
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 2 bajty
Zakres wartości: Od  32768 do 32767
Short jest 16-bitowym typem danych całkowitoliczbowych ze znakiem. W wersjach języka
Visual Basic sprzed wprowadzenia technologii .NET funkcję 16-bitowego typu całkowitolicz-
bowego ze znakiem pełnił inny typ danych, Integer; typ danych Short w ogóle nie wystę-
pował w tamtych wydaniach Visual Basica.
Stałe egzemplarze typu Short należy oznaczać wielką literą S dołączaną na końcu wartości
numerycznej:
Dim startingValue As Short = 123S
Typ danych Single
Podstawowe fakty
Podstawowy typ .NET: System.Single
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 4 bajty
Zakres wartości: Od  3.402823E+38 do  1.401298E 45 w przypadku liczb ujemnych; od
1.401298E 45 do 3.402823E+38 w przypadku liczb dodatnich
Wartości typu Single są zgodne ze standardem IEEE dla 32-bitowych (4-bajtowych) liczb
zmiennoprzecinkowych pojedynczej precyzji ze znakiem. Mimo stosunkowo dużego prze-
działu obsługiwanych wartości, stosując typ danych Single, musimy się liczyć z utratą precyzji
w pewnych obliczeniach matematycznych.
Stałe egzemplarze typu danych Single należy oznaczać wielką literą F lub znakiem wykrzyk-
nika (!) dołączanym bezpośrednio po wartościach numerycznych:
Dim startingValue As Single = 123.45F
Dim endingValue As Single = 543.21!
Znak wykrzyknika (!) można stosować także do oznaczania deklarowanych zmiennych jako
egzemplarzy typu Single:
Dim startingValue! = 123.45F
Typ danych String
Podstawowe fakty
Podstawowy typ .NET: System.String
Implementacja: Typ referencyjny (klasa)
Ilość zajmowanej pamięci: 10 + (2 * długość_łańcucha) bajtów
Zakres wartości: Od zera do około dwóch miliardów znaków Unicode
Typ danych String umożliwia reprezentowanie łańcuchów znakowych zmiennej długości
złożonych maksymalnie z około dwóch miliardów znaków.
86 | Rozdział 4. Zmienne i typy danych
Wszystkie łańcuchy w technologii .NET są niezmienne (ang. immutable). Oznacza to, że warto-
ści raz przypisanej zmiennej łańcuchowej nie można zmieniać. Kiedy modyfikujemy zawartość
łańcucha, typ danych String zwraca nowy egzemplarz uwzględniający wprowadzone zmiany.
Zmienna String zawierająca pojedynczy znak nie jest tożsama ze zmienną typu Char zawie-
rającą ten sam pojedynczy znak. Ponieważ są to dwa zupełnie różne typy, ewentualne prze-
noszenie danych pomiędzy zmiennymi tych typów wymaga stosownej konwersji (jeśli włą-
czono opcję Option Strict).
Typ danych UInt32 (UInteger)
Podstawowe fakty
Podstawowy typ .NET: System.Int32
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 4 bajty
Zakres wartości: Od 0 do 4 294 967 295 (bez znaku)
Nowość w wersji 2005. UInteger jest 32-bitowym typem danych całkowitoliczbowych bez
znaku. Typ UInteger jest więc odpowiednikiem bez znaku opisanego wcześniej typu danych
Integer (ze znakiem).
UInteger jest jednym z czterech typów danych dodanych do języka programowania Visual
Basic w wydaniu z roku 2005, które nie są wymienione w minimalnej specyfikacji wspólnego
języka (CLS). W związku z tym, komponenty i aplikacje zbudowane według zaleceń tego
minimalnego standardu mogą nie być kompatybilne z aplikacjami wykorzystującymi ten typ
danych.
Typ danych UInt64 (ULong)
Podstawowe fakty
Podstawowy typ .NET: System.Int64
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 8 bajtów
Zakres wartości: Od 0 do 18 446 744 073 709 551 615 (bez znaku)
Nowość w wersji 2005. ULong jest 64-bitowym typem danych całkowitoliczbowych bez zna-
ku. Typ ULong jest więc odpowiednikiem bez znaku opisanego wcześniej typu danych Long
(ze znakiem).
ULong jest jednym z czterech typów danych dodanych do języka programowania Visual Basic
w wydaniu z roku 2005, które nie są wymienione w minimalnej specyfikacji wspólnego języka
(CLS). W związku z tym, komponenty i aplikacje zbudowane według zaleceń tego minimal-
nego standardu mogą nie być kompatybilne z aplikacjami wykorzystującymi ten typ danych.
Typ danych UInt16 (UShort)
Podstawowe fakty
Podstawowy typ .NET: System.Int64
Implementacja: Typ wartościowy (struktura)
Ilość zajmowanej pamięci: 2 bajty
Zakres wartości: Od 0 do 65535 (bez znaku)
Typy danych | 87
Nowość w wersji 2005. UShort jest 16-bitowym typem danych całkowitoliczbowych bez znaku.
Typ UShort jest więc odpowiednikiem bez znaku opisanego wcześniej typu danych Short
(ze znakiem).
UShort jest jednym z czterech typów danych dodanych do języka programowania Visual Basic
w wydaniu z roku 2005, które nie są wymienione w minimalnej specyfikacji wspólnego języka
(CLS). W związku z tym, komponenty i aplikacje zbudowane według zaleceń tego minimal-
nego standardu mogą nie być kompatybilne z aplikacjami wykorzystującymi ten typ danych.
Typy danych definiowane przez użytkownika
Chociaż pojedyncze zmienne w zdecydowanej większości przypadków zaspokajają potrzeby
programistów, nierzadko bardziej efektywnym rozwiązaniem jest łączenie wielu podstawowych
wartości danych w ramach logicznych grup. Te niestandardowe typy danych (definiowane
przez użytkownika) rozszerzają zbiór podstawowych typów danych o nowe typy dostosowane
do potrzeb konkretnych programów.
Wersje języka Visual Basic sprzed wprowadzenia technologii .NET oferowały możliwość two-
rzenia typów danych definiowanych przez użytkownika za pośrednictwem wyrażenia Type.
Budowane w ten sposób struktury danych były zwykłymi grupami zmiennych pozbawio-
nymi jakiejkolwiek funkcjonalności (oczywiście poza możliwością ustawiania i odczytywania
wartości reprezentowanych w poszczególnych składowych). W wydaniach Visual Basica
wchodzących w skład platformy .NET Framework znacznie rozszerzono tego rodzaju mechani-
zmy, implementując możliwość definiowania kodu zarówno we wspomnianych strukturach
danych, jak i podstawowych elementach platformy .NET. Typy znane z Visual Basica 6 zastą-
piono konstrukcjami powszechnie stosowanymi w technologii .NET  strukturami (definio-
wanymi ze słowem kluczowym Structure).
Podstawową konstrukcją gromadzącą kod i dane w platformie .NET jest klasa. Klasy pod
wieloma względami przypominają struktury, ale są wolne od pewnych ograniczeń, które
dotyczą wyłącznie struktur. Bodaj najważniejszą różnicą dzielącą struktury od klas jest to, że
w przeciwieństwie do klas (które implementują typy referencyjne), struktury implementują
typy wartościowe (dziedziczące bezpośrednio po typie System.ValueType).
Aby zadeklarować strukturę, należy użyć wyrażenia Structure:
[Public|Private|Friend] Structure structureName
deklaracje składowych
End Structure
Składowymi struktury mogą być pola, właściwości, metody, zdarzenia dzielone, typy wylicze-
niowe oraz inne, zagnieżdżone struktury. Każda ze składowych musi zostać zadeklarowana
z jednym z trzech modyfikatorów dostępu: Public, Private lub Friend.
Najprostszym i najczęściej spotykanym zastosowaniem struktur jest grupowanie wzajemnie
powiązanych zmiennych (nazywanych polami). Przykładowo, w naszym programie możemy
korzystać z prostej struktury definiującej podstawowe informacje o jednej osobie:
Structure Person
Public Name As String
Public Address As String
Public City As String
Public State As String
Public Zip As String
Public Age As Short
End Structure
88 | Rozdział 4. Zmienne i typy danych
Poniżej przedstawiono standardową deklarację definiującą zmienną typu Person:
Dim onePerson As Person
Dostęp do składowych struktury wymaga użycia standardowej składni  z kropką , która jest
stosowana także w przypadku składowych klas:
onePerson.Name = "Beethoven"
Bardziej złożone struktury mogą zawierać zarówno proste pola składowe, jak i właściwości:
Public Structure NameAndState
' ----- Pola publiczne i prywatne.
Public Name As String
Private theState As String
Public Function ShowAll( ) As String
' ----- Metoda publiczna. Wyświetla wszystkie składowane wartości.
If (theState = "") And (Name = "") Then
Return " from "
ElseIf (theState = "") Then
Return Name & " from "
ElseIf (Name = "") Then
Return " from " & theState
Else
Return Name & " from " & theState
End If
End Function
Public Property State( ) As String
' ----- Właściwość publiczna. Ogranicza zbiór wartości reprezentujących stany.
Get
Return theState
End Get
Set(ByVal value As String)
If (Len(value) = 2) Then
theState = UCase(value)
Else
Throw New System.ArgumentException( _
"Stan musi być reprezentowany przez dwa znaki.", "State")
End If
End Set
End Property
End Structure
Egzemplarze tej struktury mogą być od tej pory tworzone i wykorzystywane dokładnie tak
jak egzemplarze klas:
Dim onePerson As New NameAndState
onePerson.Name = "Donna"
onePerson.State = "CA"
MsgBox(onePerson.ShowAll())
Struktury mogą być przekazywane na wejściu funkcji w formie argumentów lub wykorzysty-
wane w roli typów zwracanych przez funkcje. Chociaż struktury pod wieloma względami przy-
pominają klasy, nie obsługują szeregu rozwiązań znanych z klas:
" Struktury nie mogą ani dziedziczyć po innych strukturach, ani same nie mogą być dzie-
dziczone.
" Wszystkie konstruktory struktur muszą pobierać parametry wejściowe.
" Struktury nie mogą definiować destruktorów (metoda Finalize i tak nigdy nie jest wy-
woływana).
Typy danych | 89
" Deklaracje składowych nie mogą inicjalizować ich wartości, stosować konstrukcji skład-
niowej As New ani określać początkowego rozmiaru tablic.
Szczegółowe omówienie terminologii programowania można znalezć w rozdziale 3.
Konwersja typów danych
Proces konwersji wartości jednego typu na wartość innego typu nazywamy rzutowaniem (ang.
casting) lub po prostu konwersją. Techniki konwersji mogą być stosowane dla wartości sta-
łych, zmiennych lub wyrażeń określonego typu. Język programowania Visual Basic oferuje
szereg funkcji konwertujących, które rzutują wartości jednego typu danych do postaci ich odpo-
wiedników innego typu danych:
Dim miniSize As Byte = 6
Dim superSize As Long
superSize = CLng(miniSize) ' Konwertuje wartość zmiennej typu Byte na wartość typu Long.
superSize = CLng("12") ' Konwertuje stałą typu String na wartość typu Long.
Rzutowania mogą mieć charakter działań rozszerzających lub zawężających. Rzutowanie
rozszerzające (ang. widening cast) ma miejsce wtedy, gdy docelowy typ danych może z powo-
dzeniem reprezentować wszystkie możliwe wartości typu zródłowego (z taką sytuacją mamy
do czynienia np. wtedy, gdy konwertujemy wartość typu Short na wartość typu Integer lub
wartość typu Integer na wartość typu Double). Rzutowanie rozszerzające nigdy nie powoduje
utraty danych. Rzutowanie zawężające (ang. narrowing cast) polega na konwersji oryginal-
nego typu danych na typ, który nie może reprezentować wszystkich możliwych danych typu
zródłowego. Rzutowanie zawężające może prowadzić do utraty części danych lub wręcz błędu
konwersji.
Konwersje typów w Visual Basicu mogą być realizowane na dwa sposoby: jawnie (wprost) lub
w ukryciu. Konwersja niejawna (ang. implicit conversion) jest realizowana przez kompilator,
jeśli okoliczności na to pozwalają (i jeśli samo rzutowanie jest prawidłowe). Przykładowo, jeśli
umieścimy w naszej aplikacji następującą sekwencję wyrażeń:
Dim smallerData As Integer = 3948
Dim largerData As Long
largerData = smallerData
wartość zmiennej smallerData automatycznie zostanie rzutowana do większego typu danych
Long (wykorzystywanego przez zmienną largerData). Ten rodzaj konwersji niejawnej po
części jest uzależniony od ustawienia wyrażenia Option Strict. Wyrażenie Option Strict
powinno się znajdować na samym początku pliku z kodem zródłowym (przed właściwym
kodem klasy):
Option Strict {On | Off}
Jeśli opcja Option Strict jest włączona (On), kompilator będzie automatycznie wykonywał
tylko rzutowania rozszerzające, co oznacza, że takie rzutowania zawężające jak:
Dim smallerData As Integer
Dim largerData As Long = 3948
smallerData = largerData
spowodują wygenerowanie błędów kompilacji (nawet jeśli faktycznie konwertowane dane mogą
być bez trudu reprezentowane przez typy zmiennych docelowych). Oznacza to, że należy zasto-
sować konwersję jawną (ang. explicit conversion):
smallerData = CInt(largerData)
90 | Rozdział 4. Zmienne i typy danych
Ustawiając wartość Off w opcji Option Strict, zezwalamy na stosowanie techniki konwersji
niejawnej nawet wtedy, gdy może to prowadzić do występowania błędów w czasie wykony-
wania programu.
Oprócz wspomnianej opcji Option Strict, Visual Basic oferuje też wyrażenie Option Explicit,
które również powinno być stosowane na początku plików z kodem zródłowym:
Option Explicit {On | Off}
Kiedy opcja Option Explicit jest włączona (On), wszystkie zmienne muszą być deklarowane
(za pomocą słowa kluczowego Dim lub innego, podobnego) przed użyciem. Kiedy opcja Option
Explicit jest wyłączona (Off), kompilator Visual Basica automatycznie doda (w czasie kompila-
cji) niezbędne deklaracje dla wszystkich nazw napotkanych zmiennych, które nie zostały
wcześniej zadeklarowane. (Nowe wyrażenia Dim nie zostaną umieszczone w naszym kodzie
zródłowym  niezbędne deklaracje zostaną dodane  po cichu w czasie kompilacji). Wyłą-
czenie tej opcji może prowadzić do występowania w programie trudnych do zlokalizowania
błędów. Więcej informacji na ten temat można znalezć w podrozdziale  Wyrażenie Option
Explicit w rozdziale 12. Wartości domyślne obu opcji (Option Strict oraz Option Expli-
cit) można ustawić we właściwościach projektu.
Język Visual Basic zawiera funkcje konwertujące dla wszystkich podstawowych typów danych.
Funkcja CBool
Konwertuje dowolny prawidłowy łańcuch lub wyrażenie numeryczne na wartość typu
Boolean. Kiedy wartość numeryczna jest konwertowana na wartość typu Boolean, wszyst-
kie liczby różne od zera są zamieniane na True i tylko zero jest zamieniane na False.
Funkcja CByte
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Byte) na wartość typu Byte, zaokrąglając ewentualną część
ułamkową.
Funkcja CChar
Konwertuje pierwszy znak łańcucha na wartość typu danych Char.
Funkcja CDate
Konwertuje dowolną prawidłową reprezentację daty lub godziny na egzemplarz typu Date.
Funkcja CDbl
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Double) na wartość typu Double.
Funkcja CDec
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Decimal) na wartość typu Decimal.
Funkcja CInt
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Integer) na wartość typu Integer, zaokrąglając ewentualną
część ułamkową.
Funkcja CLng
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Long) na wartość typu Long, zaokrąglając ewentualną część
ułamkową.
Typy danych | 91
Funkcja CObj
Konwertuje dowolne wyrażenie na egzemplarz typu Object. Takie rozwiązanie jest uza-
sadnione w sytuacji, gdy chcemy, aby typ wartościowy był traktowany jak typ referen-
cyjny.
Funkcja CSByte
Nowość w wersji 2005. Konwertuje dowolne wyrażenie numeryczne (którego wartość nale-
ży do przedziału obsługiwanego przez typ danych SByte) na wartość typu SByte, zaokrą-
glając ewentualną część ułamkową.
Funkcja CShort
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Short) na wartość typu Short, zaokrąglając ewentualną część
ułamkową.
Funkcja CSng
Konwertuje dowolne wyrażenie numeryczne (którego wartość należy do przedziału obsłu-
giwanego przez typ danych Single) na wartość typu Single.
Funkcja CStr
Konwertuje wyrażenie na jego reprezentację łańcuchową. Przykładowo, wartości typu Boole-
an mogą być konwertowane na dwa łańcuchy: "True" lub "False". Daty są konwertowane
na właściwe łańcuchy zgodnie z formatem zdefiniowanym w ramach ustawień regional-
nych danego komputera.
Funkcja CType
Oferuje uniwersalny mechanizm rzutowania, za pomocą którego obiekt lub wyrażenie do-
wolnego typu można przekształcać w odpowiednik innego typu. Funkcja CType może
być stosowana dla wszystkich klas, struktur i interfejsów. Co więcej, okazuje się, że funkcja
CType sprawdza się zarówno w przypadku podstawowych typów danych, jak i typów
(w tym klas) definiowanych przez użytkownika. Poniżej przedstawiono składnię tej funkcji:
CType(wyrażenie, nazwa-typu)
Przykładowo, poniższe wyrażenie:
Dim targetNumber As Integer = CType("12", Integer)
jest odpowiednikiem następującego wyrażenia:
Dim targetNumber As Integer = CInt("12")
Nowość w wersji 2005. W wydaniu Visual Basica z 2005 roku dodano mechanizm przecią-
żania operatorów, który szczegółowo omówimy w rozdziale 5. Jednym z elementów prze-
ciążania operatorów jest możliwość definiowania reguł konwersji funkcji CType dla własnych,
niestandardowych klas.
Funkcja CUInteger
Nowość w wersji 2005. Konwertuje dowolne wyrażenie numeryczne (którego wartość
należy do przedziału obsługiwanego przez typ danych UInteger) na wartość typu UInteger,
zaokrąglając ewentualną część ułamkową.
Funkcja CULong
Nowość w wersji 2005. Konwertuje dowolne wyrażenie numeryczne (którego wartość
należy do przedziału obsługiwanego przez typ danych ULong) na wartość typu ULong,
zaokrąglając ewentualną część ułamkową.
92 | Rozdział 4. Zmienne i typy danych
Funkcja CUShort
Nowość w wersji 2005. Konwertuje dowolne wyrażenie numeryczne (którego wartość na-
leży do przedziału obsługiwanego przez typ danych UShort) na wartość typu UShort,
zaokrąglając ewentualną część ułamkową.
Zmienne
Zmienną (ang. variable) można zdefiniować jako konstrukcję posiadającą następujące własności:
Nazwę
Nazwa zmiennej jest wykorzystywana do jej identyfikowania w kodzie zródłowym. W języku
programowania Visual Basic nazwa zmiennej musi się rozpoczynać albo od litery alfa-
betu (odpowiedniego znaku Unicode), albo od znaku podkreślenia poprzedzającego kolejny
znak podkreślenia lub dowolny znak Unicode (literę alfabetu, cyfrę, znak formatujący lub
kombinację różnych znaków). Wraz z wprowadzeniem technologii .NET firma Microsoft
zaproponowała nowy zbiór standardów nazewnictwa, które należy stosować w przypadku
zmiennych i innych nazywanych obiektów. Wspomniane standardy omówiliśmy już w punk-
cie  Konwencje nazewnicze w rozdziale 1.
Adres
Każda zmienna ma przypisany adres pamięciowy, czyli miejsce składowania jej wartości.
Zmienne stosowane w platformie .NET nie dają nam gwarancji, że reprezentowane dane
będą stale składowane pod tymi samymi adresami, zatem same adresy zmiennych nie po-
winny być rejestrowane ani wykorzystywane.
Typ danych
Typ danych zmiennej określa zakres możliwych wartości, które mogą być przez tę zmien-
ną reprezentowane.
Wartość
Wartość zmiennej jest jej właściwą zawartością składowaną pod odpowiednim adresem
pamięciowym. Wartość zmiennej określa się czasem mianem r-wartości (ang. r-value),
ponieważ zawsze występuje po prawej stronie operatora przypisania. Przykładowo, poniż-
sze wyrażenie:
Dim targetValue As Integer = 5
można odczytać w następujący sposób:  Zapisz wartość 5 w pamięci, pod adresem repre-
zentowanym przez zmienną targetValue . Ponieważ nazwy zmiennej targetValue użyto
na lewo od operatora przypisania, zmienna (lub jej lokalizacja w pamięci) bywa nazywana
l-wartością (ang. l-value).
Zakres
Zakres zmiennej określa miejsca programu, w których dana zmienna będzie widoczna
z perspektywy kodu zródłowego. Zakres zmiennych omówimy bardziej szczegółowo w dal-
szej części tego rozdziału.
Czas życia
Od czasu życia zmiennej zależy to, kiedy i jak długo dana zmienna będzie istniała. Okazuje
się, że zmienna może, ale nie musi być widoczna (należeć do bieżącego zakresu) w całym
czasie życia. Także czas życia zmiennych zostanie szczegółowo przeanalizowany w dalszej
części tego rozdziału.
Zmienne | 93
Deklaracja zmiennej
Deklaracja zmiennej (ang. variable declaration) ma na celu związanie jej nazwy z określonym
typem danych. W przypadku zmiennych nieobiektowych (typów wartościowych) deklaracja
jest równoznaczna z utworzeniem egzemplarza danej zmiennej. Przykładowo, deklaracja
w postaci:
Dim createMeNow As Integer
tworzy zmienną typu Integer nazwaną createMeNow. Powyższa deklaracja jest równoważna
poniższemu wyrażeniu:
Dim createMeNow As Integer = New Integer
lub nawet wyrażeniu w postaci:
Dim createMeNow As New Integer
w którym położono nacisk na sam fakt tworzenia nowego egzemplarza obiektu zmiennej.
Za pomocą pojedynczych wyrażeń można deklarować wiele zmiennych. Ogólnie, mimo że typ
każdej z deklarowanych zmiennych może być inny, każdorazowe stosowanie nazw typów nie
jest bezwzględnie wymagane. Jeśli w deklaracji zmiennej zrezygnujemy z jawnego określenia
typu, wówczas zostanie zastosowany typ kolejnej zmiennej, dla której w sposób bezpośredni
zadeklarowano właściwy typ. Przykładowo, poniższy wiersz kodu:
Dim first As Long, second, third As Integer, fourth As String
deklaruje między innymi zmienne second i third typu Integer (w Visual Basicu 6 second
byłaby zmienną typu Variant).
Visual Basic oferuje możliwość inicjalizacji zmiennych w wierszach ich deklarowania. (Przy-
pisywana wartość bywa nazywana wartością inicjalizującą  ang. initializer). Przykładowo,
poniższe wyrażenie:
Dim alwaysInitialized As Integer = 5
deklaruje i tworzy zmienną typu Integer, po czym przypisuje jej wartość początkową równą 5.
Okazuje się, że pojedyncze wyrażenia mogą zawierać także wiele operacji przypisania:
Dim first As Integer = 6, second As Integer = 9
Warto pamiętać, że w przypadku stosowania wartości inicjalizujących dla każdej ze zmien-
nych należy wprost określić typ danych.
Zmienne obiektowe (zmienne typów referencyjnych) deklarujemy dokładnie tak samo jak ich
odpowiedniki ze świata podstawowych typów danych:
Dim newHire As Employee
Przedstawiona deklaracja nie tworzy jednak zmiennej obiektowej  po wykonaniu tego wyra-
żenia zmienna newHire będzie miała wartość Nothing. Utworzenie obiektu wymaga jawnego
wywołania konstruktora odpowiedniej klasy na następujące sposoby:
Dim newHire As New Employee
lub:
Dim newHire As Employee = New Employee
lub nawet:
Dim newHire As Employee
newHire = New Employee
94 | Rozdział 4. Zmienne i typy danych
Zakres, czas życia i poziom dostępu do zmiennych
Każda zmienna ma swój zakres (ang. scope), który określa, w którym miejscu (lub miejscach)
programu jej identyfikator jest właściwie rozpoznawany  gdzie w kodzie zródłowym dana
zmienna jest widoczna.
Zmienne lokalne: zakresy obejmujące blok kodu lub procedurę
Wszystkie zmienne deklarowane wewnątrz funkcji, procedur bądz właściwości nazywamy
zmiennymi lokalnymi (ang. local variables). Tego rodzaju zmienne mogą być wykorzystywane
wyłącznie w ramach odpowiednich funkcji, procedur i właściwości  kiedy ich wykonywa-
nie się zakończy, wszelkie zmienne lokalne związane z tymi konstrukcjami przestają istnieć
(oczywiście jeśli nie zostały przekazane do innej zmiennej charakteryzującej się szerszym za-
kresem).
Ogólnie, zmienne lokalne charakteryzują się zakresem na poziomie procedury  są dostępne
z poziomu wszystkich wierszy kodu wchodzących w skład odpowiedniej procedury. Dekla-
racje zmiennych lokalnych z reguły występują na samym początku procedur lub funkcji
(w kodzie wykonywanym bezpośrednio po wywołaniu tych konstrukcji):
Public Sub DoTheWork( )
Dim localInt As Integer
Dim localEmp As New Employee
Bloki kodu są zbiorami wyrażeń zawartymi w ramach wyrażeń warunkowych If, w pętlach
For, pętlach With i innych podobnych konstrukcjach języka programowania, dla których sto-
suje się odrębne wyrażenia otwierające i zamykające. Wszystkie wyrażenia zdefiniowane
pomiędzy wyrażeniami otwierającymi (If, ElseIf, For, With itp.) i zamykającymi (End If,
Next, End With itp.) są częścią odpowiednich bloków kodu. Co więcej, zmienna zdefiniowana
wewnątrz bloku kodu charakteryzuje się zakresem na poziomie bloku i jako taka jest widocz-
na tylko w ramach tego bloku. Ponieważ bloki kodu mogą być zagnieżdżane, zmienne lokalne
definiowane na poziomie tych bloków mogą występować dowolnie głęboko w hierarchii tego
rodzaju zagnieżdżeń.
Public Sub DoTheWork(ByVal fromWhen As Date, ByVal howMuch As Decimal)
If (fromWhen < Today) Then
' ----- Ta zmienna jest dostępna tylko w skrajnie zewnętrznym bloku If,
' który dodatkowo zawiera skrajnie wewnętrzny blok If. Zmienna nie
' jest dostępna poza skrajnie zewnętrznym blokiem If.
Dim simpleCalculation As Integer
If (howMuch > 0@) Then
' ----- Ta zmienna jest dostępna tylko w skrajnie wewnętrznym
' bloku If.
Dim complexCalculation As Integer
End If
End If
End Sub
Zmienne dostępne na poziomie bloków w ogóle nie są widoczne spoza bloków, w których
zostały zdefiniowane. Przeanalizujmy teraz następujący blok kodu:
If (origValue <> 0) Then
Dim inverseValue As Decimal
inverseValue = 1 / origValue
End If
' ----- Poniższe wyrażenie zostanie odrzucone przez kompilator.
MsgBox(CStr(inverseValue))
Zmienne | 95
W powyższym kodzie zmienna inverseValue nie będzie rozpoznawana poza blokiem kodu,
w którym została zdefiniowana, zatem ostatni wiersz przedstawionego kodu spowoduje błąd
kompilacji.
Wszystkie zmienne lokalne, niezależnie od tego, czy deklarujemy ja na poziomie bloków kodu,
czy na poziomie procedur, charakteryzują się czasem życia równym czasowi życia swoich
procedur (lub funkcji). Oznacza to, że zmienne deklarowane na poziomie bloków kodu zacho-
wują swoje wartości przez cały czas życia procedury, która ten blok kodu zawiera (także
w czasie wykonywania kodu spoza tego bloku). Przykładowo, w poniższym kodzie:
Dim counter As Integer
For counter = 1 To 5
If (ProcessData(counter) = True) Then
Dim soFar1 As Integer
Dim soFar2 As Integer = 0
soFar1 += 1
soFar2 += 1
MsgBox("Status na tym etapie: " & soFar1 & ", " & soFar2)
End If
Next counter
zmienna soFar1 zachowuje swoją wartość z poprzedniego wykonania bloku If, w którym
została zadeklarowana (z poprzedniej iteracji pętli For). W chwili wyświetlania pierwszego
komunikatu wspomniana zmienna będzie zawierała wartość 1, w czasie wyświetlania drugiego
komunikatu będzie zawierała wartość 2 itd. Ponieważ zmienną soFar2 zadeklarowano z warto-
ścią inicjalizującą, wartość tej zmiennej będzie ponownie ustawiana (w tym przypadku zero-
wana) w każdej kolejnej iteracji pętli For. Oznacza to, że wszystkie wyświetlane komunikaty
będą zawierały wartość 1 na drugiej pozycji.
Procedura może wykorzystywać zmienne przekazywane na jej wejściu za pośrednictwem argu-
mentów. Zakres tego rodzaju zmiennych zawsze ogranicza się do poziomu danej procedury.
Czas życia zmiennych lokalnych może wykraczać poza czas wykonywania procedury, w której
te zmienne zadeklarowano. Przykładowo, zmienne statyczne (mimo lokalnego zakresu)  żyją
przez cały czas istnienia klasy lub modułu, do którego należą. Tego rodzaju zmienne należy
deklarować ze słowem kluczowym Static (zamiast ze standardowym słowem kluczowym Dim):
Static longLasting As Integer = 0
Wartość inicjalizująca zmiennej statycznej jest stosowana w momencie tworzenia egzempla-
rza odpowiedniej klasy lub modułu (nie każdorazowo w chwili napotkania odpowiedniej
deklaracji). Kiedy wchodzimy do procedury zawierającej jakąś zmienną statyczną, wspomniana
zmienna będzie zawierała dokładnie tę samą wartość, którą zawierała podczas poprzedniego
wykonywania danej procedury. Zmienne statyczne nie mogą być stosowane w procedurach
składowych struktur.
Zakres i poziomy dostępu w ramach modułów
Wszystkie zmienne deklarowane wewnątrz klas (a także struktur i modułów), ale poza jakimi-
kolwiek procedurami składowymi, charakteryzują się zakresem na poziomie typu i jako takie
są dostępne z poziomu wszystkich procedur i funkcji wchodzących w skład tej samej klasy
(lub struktury bądz modułu). Warto jednak pamiętać o możliwości prostego rozszerzania tego
zakresu (poza poziom typu) za pomocą modyfikatorów dostępu (ang. access modifier).
96 | Rozdział 4. Zmienne i typy danych
Dla każdej zmiennej deklarowanej na poziomie typu należy stosować słowo kluczowe mody-
fikatora dostępu. (Równie dobrze można się posługiwać słowem kluczowym Dim, jednak wów-
czas poziom dostępu będzie uzależniony od typów modułów, co może uczynić nasz kod nieczy-
telnym). Modyfikatory dostępu przydzielają dostęp na poszczególnych poziomach stopniowo 
modyfikator Poblic jest w tym względzie najmniej restrykcyjny (patrz tabela 4.1).
Tabela 4.1. Modyfikatory dostępu
Modyfikator dostępu Opis
Public
Zmienne publiczne są dostępne z poziomu dowolnego kodu, który ma dostęp do egzemplarza klasy
bądz struktury lub do typu zawierającego te zmienne. Jeśli jakaś klasa zawiera zmienną publiczną
i jeśli egzemplarz tej klasy jest dostępny z poziomu odrębnego projektu, aplikacji lub komponentu, także
ta zmienna będzie dostępna z poziomu kodu klienckiego.
Protected
Zmienne chronione są dostępne zarówno w ramach klasy, w której zostały zadeklarowane,
jak i z poziomu wszelkich klas potomnych względem tej klasy (ale nie spoza łańcucha klas związanych
relacją dziedziczenia). Zmienne chronione mogą być deklarowane wyłącznie w klasach (nie można
ich stosować w strukturach ani modułach).
Friend
Zmienne zaprzyjaznione są dostępne z dowolnego miejsca w tym samym podzespole, ale nigdy spoza
podzespołu  egzemplarze klasy zawierającej zmienne zaprzyjaznione ukrywają te zmienne przed kodem
zewnętrznym nawet wtedy, gdy same są przez ten kod wykorzystywane. Zmienne zaprzyjaznione
mogą być stosowane w klasach, strukturach i modułach.
Protected Friend
Stosowanie kombinacji słów kluczowych Protected i Friend powoduje, że tak deklarowane zmienne
mają cechy zarówno zmiennych chronionych, jak i zmiennych zaprzyjaznionych  są dostępne
w ramach klasy i klas potomnych oraz w ramach tego samego podzespołu (ale nigdy poza tym
podzespołem). Chronione zmienne zaprzyjaznione mogą być stosowane wyłącznie w klasach (nie można
ich stosować w strukturach ani modułach).
Private
Zmienne prywatne są dostępne z dowolnego punktu tej samej klasy, struktury lub modułu, ale nigdy
poza swoją macierzystą konstrukcją. Zmienne prywatne są ukrywane nawet przed składowymi klas
potomnych.
Czas życia zmiennych deklarowanych na poziomie typów obejmuje cały czas życia egzem-
plarza klasy, struktury lub modułu, do którego należą. Zmienne można deklarować jako dzielo-
ne (ze słowem kluczowym Shared) i  tym samym  umożliwić istnienie odpowiednich
wartości bez konieczności tworzenia egzemplarza klasy, struktury lub modułu. Warto jednak
pamiętać, że czas życia zmiennych dzielonych rozciąga się na cały okres funkcjonowania aplika-
cji. Wszystkie zmienne deklarowane w ciele modułu domyślnie są składowymi dzielonymi.
Stałe
Stałe (ang. constants) są w istocie zmiennymi dostępnymi tylko do odczytu. Raz ustawionej
w kodzie programu wartości zmiennej (w czasie kompilacji) nie można zmieniać. Stałe są defi-
niowane na poziomie lokalnym lub poziomie modułu za pomocą słowa kluczowego Const:
modyfikatorDostępu Const nazwa As typ = wartość
gdzie modyfikatorDostępu jest jednym z opisanych w poprzednim podrozdziale modyfika-
torów dostępu. (Modyfikatory dostępu nie są stosowane w przypadku stałych deklarowanych
wewnątrz procedur). Kiedy opcja Option Strinct jest włączona (ma wartość On), wszystkie
stałe muszą być deklarowane z konkretnym typem.
Stałe | 97
Typy wyliczeniowe
Typ wyliczeniowy (ang. enumeration) jest grupą wzajemnie powiązanych stałych całkowito-
liczbowych. Wszystkie składowe wyliczenia muszą być nie tylko egzemplarzami tego samego
typu danych, ale też typu całkowitoliczbowego (Byte, Integer, Long lub Short, a w wersji
2005 lub nowszej również SByte, UInteger, ULong lub UShort). Składowe typu wyliczeniowego
są elementami dzielonymi i dostępnymi tylko do odczytu przez cały czas życia aplikacji.
Public Enum VehicleType As Integer
bicycle = 2
tricycle = 3
passengerCar = 4
eighteenWheeler = 18
End Enum
Składowe typu wyliczeniowego można stosować w kodzie dokładnie tak jak stałe i zmienne:
Dim whatIDrive As VehicleType
whatIDrive = VehicleType.passengerCar
Typy wyliczeniowe mogą być deklarowane wyłącznie na poziomie przestrzeni nazw lub modułu
(w żadnym razie nie można ich deklarować wewnątrz procedur).
Tablice
Tablica w wielu językach programowania (włącznie z językiem Visual Basic) jest podstawową
strukturą danych. Tablice umożliwiają składowanie kolekcji egzemplarzy podobnych typów
danych lub obiektów. Każdy element znajduje się na pozycji oznaczonej unikatowym nume-
rem. W Visual Basicu indeksy tablic rozpoczynają się od zera (zero jest dolną granicą) i kończą
na zdefiniowanej górnej granicy.
Poniższe przykłady ilustrują rozmaite sposoby deklarowania tablic jednowymiarowych:
' Konstruktor niejawny: Brak rozmiaru początkowego i wartości inicjalizujących.
Dim days() As Integer
' Konstruktor jawny: Brak rozmiaru początkowego i wartości inicjalizujących.
Dim days() As Integer = New Integer( ) {}
' Konstruktor niejawny: Obecność rozmiaru początkowego, brak wartości inicjalizujących.
Dim days(6) As Integer
' Konstruktor jawny: Obecność rozmiaru początkowego, brak wartości inicjalizujących.
Dim days() As Integer = New Integer(6) {}
' Konstruktor niejawny: Rozmiar początkowy wynikający z obecności wartości inicjalizujących.
Dim days() As Integer = {1, 2, 3, 4, 5, 6, 7}
' Konstruktor jawny: Rozmiar początkowy i wartości inicjalizujące.
Dim days() As Integer = New Integer(6) {1, 2, 3, 4, 5, 6, 7}
Deklaracja tablicy może:
" wywołać (w sposób jawny lub niejawny) konstruktor tablicy;
" określić początkowy rozmiar wszystkich wymiarów tablicy lub pozostawić wszystkie roz-
miary nieokreślone;
" zainicjalizować elementy tablicy lub pozostawić ich wartości nieokreślone.
98 | Rozdział 4. Zmienne i typy danych
W Visual Basicu 6 programista mógł określać zarówno dolne, jak i górne granice dla wszystkich
wymiarów tablicy. W języku Visual Basic .NET dolną granicą (najniższym indeksem) wszystkich
tablic jest zero. Przykładowo, wyrażenie w postaci:
Dim myArray(5) As Integer
deklaruje tablicę złożoną z sześciu elementów, gdzie indeks pierwszego będzie równy 0,
a indeks ostatniego będzie równy 5.
Tablice mogą się składać z wielu wymiarów (ang. dimensions). Przykładowo, poniższy wiersz
deklaruje i inicjalizuje tablicę dwuwymiarową:
Dim rectArray(,) As Integer = {{1, 2, 3}, {4, 5, 6}}
Poniższy fragment kodu wyświetla zawartość tej tablicy:
Debug.Write(rectArray(0, 0))
Debug.Write(rectArray(0, 1))
Debug.WriteLine(rectArray(0, 2))
Debug.Write(rectArray(1, 0))
Debug.Write(rectArray(1, 1))
Debug.WriteLine(rectArray(1, 2))
' ----- Poniżej przedstawiono dane wyjściowe:
123
456
Górną granicę każdego z wymiarów tablicy można zmodyfikować za pomocą wyrażenia ReDim,
którego ogólną składnię przedstawiono poniżej:
ReDim [Preserve] nazwaTablicy(nowaGórnaGranica)
Kwalifikator Preserve powoduje, że wszystkie wartości, które istnieją w momencie wykony-
wania wyrażenia ReDim, zostaną zachowane w tablicy; w razie braku tego kwalifikatora cała
tablica zostanie wyczyszczona. Jeśli zdecydujemy się użyć tego kwalifikatora, powinniśmy
pamiętać, że modyfikacja górnej granicy może dotyczyć tylko ostatniego wymiaru tablicy.
Liczba samych wymiarów tablicy nigdy nie może być zmieniana.
Dolną i górną granicę danego wymiaru tablicy można określić odpowiednio za pomocą funkcji
LBound oraz UBound:
Dim smallArray(5) As Integer
MsgBox(UBound(smallArray)) ' Wyświetla liczbę 5.
Ponieważ dolną granicą wszystkich wymiarów tablicy jest indeks zerowy, funkcja LBound
zawsze będzie zwracała właśnie zero.
Kolekcje
Visual Basic oferuje programiście obiekt tablicy asocjacyjnej nazwany kolekcją (ang. collection).
Mimo wielu istotnych podobieństw do standardowych tablic, włącznie z występowaniem
elementów w określonym porządku, warto pamiętać o tym, co odróżnia kolekcję od tablic: jej
elementy mają postać par klucz-wartość. Elementy kolekcji można identyfikować zarówno
według pozycji, jak i według klucza, lub stosując technikę iteracyjnego przeszukiwania kolej-
nych pozycji.
Szczególnie przydatna w codziennej pracy z kolekcjami okazuje się piątka składowych klasy
Collection:
Kolekcje | 99
Metoda Add
Dodaje element do kolekcji. Poza samymi danymi można określić opcjonalny klucz, za
pośrednictwem którego będzie się można odwoływać do nowego elementu.
Metoda Clear
Usuwa wszystkie elementy z kolekcji.
Właściwość Count
Zwraca liczbę elementów składowanych w kolekcji.
Właściwość Item
Zwraca pojedynczy element składowany w kolekcji i identyfikowany albo według indeksu
(pozycji w ramach kolekcji), albo według klucza (jeśli został określony w chwili dodawa-
nia tego elementu do kolekcji).
Metoda Remove
Usuwa z kolekcji element na podstawie przekazanego indeksu bądz klucza.
Poniższy fragment kodu definiuje kolekcję reprezentującą nazwy stanów identyfikowane za
pomocą popularnych skrótów (w tym przypadku skróty występują w roli kluczy):
Dim states As New Collection
states.Add("New York", "NY")
states.Add("Michigan", "MI")
Elementy tej kolekcji można przeszukiwać iteracyjnie za pomocą prostej konstrukcji For
Each...Next:
Dim oneState As String
For Each oneState In states
MsgBox(oneState)
Next oneState
Podobnie jak w przypadku tablic, dostęp do elementów składowych kolekcji można uzyskiwać
za pośrednictwem odpowiednich wartości indeksu. Dolna granica indeksu kolekcji zawsze
wynosi jeden.
Nowość w wersji 2005. W wersji języka Visual Basic wydanej w roku 2005 wprowadzono typy
uniwersalne, które umożliwiają wiązanie egzemplarzy kolekcji (i innych klas) z konkretnymi
typami danych w czasie wykonywania programu. Więcej informacji na ten temat można
znalezć w rozdziale 10.
Parametry i argumenty
Chociaż procedury są autonomicznymi blokami kodu, ich prawidłowe funkcjonowanie czę-
sto wymaga interakcji z danymi spoza samych procedur. Dane zewnętrzne można przeka-
zywać do procedur za pośrednictwem tzw. listy parametrów. Listę parametrów definiujemy
w wierszu deklaracji procedury (w nawiasie, bezpośrednio za nazwą samej procedury):
Public Function RepeatString(ByVal origText As String, _
ByVal howManyTimes As Integer) As String
' ----- Zwraca łańcuch wielokrotnie skonkatenowany z samym sobą.
Dim counter As Integer
RepeatString = ""
For counter = 1 To howManyTimes
RepeatString &= origText
Next counter
End Function
100 | Rozdział 4. Zmienne i typy danych
Funkcja RepeatString otrzymuje na wejściu dwa parametry: origText oraz howManyTimes. Dla
każdego parametru określono zarówno typ danych, jak i metodę przekazywania. Metoda przeka-
zywania parametru to albo ByVal (przez wartość), albo ByRef (przez referencję). W technologii
.NET domyślnym sposobem przekazywania parametrów jest przekazywanie przez wartość.
Podczas wywoływania procedury pobierającej parametry przekazujemy na jej wejściu warto-
ści, które na poziomie kodu wywołującego z reguły nazywa się argumentami. Przykładowo,
poniższe wyrażenie dołącza dwa argumenty do wywołania funkcji RepeatString: łańcuch
"abc" oraz liczbę całkowitą 5:
targetString = RepeatString("abc", 5)
Ponieważ w technologii .NET klasy mogą zawierać metody przeciążone, argumenty przekazy-
wane przez nas na wejściu procedury muszą odpowiadać sygnaturze dokładnie jednej z prze-
ciążonych wersji wywoływanej metody. Bardziej szczegółowe omówienie techniki przeciąża-
nia można znalezć w rozdziale 3.
Przekazywanie argumentów
Wszystkie argumenty są przekazywane albo przez wartość, albo przez referencję (w zależności
od tego, czy przed nazwą odpowiedniego parametru użyjemy słowa kluczowego ByVal, czy
ByRef). Kiedy dane są przekazywane przez wartość, docelowa procedura otrzymuje kopię
wyrażenia lub zmiennej zródłowej. W samej procedurze parametr jest traktowany dokładnie
tak jak zmienna lokalna  może być dowolnie wykorzystywany i modyfikowany, ale prze-
staje istnieć w chwili zakończenia wykonywania procedury. Żadna ze zmian wartości parame-
trów przekazanych przez wartość (zadeklarowanych ze słowem kluczowym ByVal) w ramach
procedury nie będzie miała wpływu na wartość zmiennej zródłowej. Opisana zasada jest szcze-
gólnie łatwa do weryfikacji w przypadku typów wartościowych. Przykładowo, przeanalizujmy
teraz następujący fragment kodu:
Public Sub ParentRoutine()
Dim sourceValue As Integer = 5
ChildRoutine(sourceValue)
MsgBox(sourceValue) ' --> Wyświetla 5
End Sub
Public Sub ChildRoutine(ByVal incoming As Integer)
incoming = 10
End Sub
Chociaż wartość zmiennej sourceValue przekazanej do procedury ChildRoutine (za pośred-
nictwem parametru incoming) została przez tę procedurę zmodyfikowana, odpowiednia zmiana
nie została propagowana do kodu procedury wywołującej ParentRoutine, ponieważ para-
metr incoming reprezentował kopię wartości zmiennej sourceValue.
Z drugiej strony, obiekty (egzemplarze typów referencyjnych) przekazywane do procedur przez
wartość mogą być przez te procedury modyfikowane. Precyzyjnie mówiąc, na poziomie pro-
cedury można modyfikować składowe przekazanego obiektu, nie sam obiekt. W przypadku
obiektów przekazywanych przez wartość w praktyce następuje przekazanie adresu pamięcio-
wego, stąd zmiany dokonywane przez procedurę na danym obszarze pamięci znajdują odzwier-
ciedlenie w oryginalnym obiekcie. Warto jednak pamiętać, że obiektu przekazanego przez
wartość nie można na poziomie procedury zastąpić innym egzemplarzem tej samej klasy (nasze
możliwości obejmują wyłącznie modyfikowanie składowych):
Parametry i argumenty | 101
Public Class DataClass
Public DataMember As Integer
End Class
Public Class CodeClass
Public Sub ParentRoutine()
Dim sourceValue As New DataClass
sourceValue.DataMember = 5
ChildRoutine(sourceValue)
MsgBox(sourceValue.DataMember) ' --> Wyświetla 10
End Sub
Public Sub ChildRoutine(ByVal incoming As DataClass)
' ----- Poniższy wiersz zmienia  rzeczywistą składową.
incoming.DataMember = 10
' ----- Poniższe wiersze nie mają wpływu na zmienną sourceValue.
incoming = New DataClass
incoming.DataMember = 15
End Sub
End Class
Przekazywanie przez referencję (za pośrednictwem parametru zadeklarowanego ze słowem
kluczowym ByRef) argumentu typu wartościowego na wejściu procedury zawsze oznacza
przekazanie adresu pamięciowego odpowiedniej wartości  oznacza to, że ewentualne
zmiany wprowadzone przez procedurę docelową będą miały bezpośredni wpływ na wartość
odpowiedniej zmiennej zródłowej. (Ten mechanizm jest stosowany pod warunkiem, że wartość
zródłowa jest składowana w zmiennej; stałe i wyrażenia obliczane w samym wywołaniu
z natury rzeczy nie mogą być modyfikowane). Przykładowo, spróbujmy porównać poniższy
kod ze słowem kluczowym ByRef z przedstawionym przed momentem odpowiednikiem zawie-
rającym parametr przekazywany przez wartość:
Public Sub ParentRoutine()
Dim sourceValue As Integer = 5
ChildRoutine(sourceValue)
MsgBox(sourceValue) ' --> Wyświetla 10
End Sub
Public Sub ChildRoutine(ByRef incoming As Integer)
incoming = 10
End Sub
Jak widać, zastąpienie słowa kluczowego ByVal słowem ByRef miało istotny wpływ na funk-
cjonowanie tego fragmentu kodu. W przypadku typów referencyjnych różnica nie jest tak
widoczna, chyba że spróbujemy w procedurze docelowej całkowicie zastąpić oryginalny
obiekt. Przekazywanie przez referencję daje taką możliwość! Wynika to z faktu, że słowo klu-
czowe ByRef wymusza przekazywanie do procedury adresu adresu pamięciowego. Modyfi-
kując ten adres pamięciowy, możemy w prosty sposób zastąpić adres reprezentowany przez
zmienną zródłową. W niektórych językach programowania opisywany schemat jest nazywany
podwójnym wskaznikiem (ang. double pointer). Wszelkie wątpliwości związane z tym mecha-
nizmem powinien wyjaśnić poniższy przykład. Warto porównać ten fragment kodu z podob-
nym fragmentem, w którym zastosowano słowo kluczowe ByVal:
Public Class DataClass
Public DataMember As Integer
End Class
Public Class CodeClass
Public Sub ParentRoutine( )
102 | Rozdział 4. Zmienne i typy danych
Dim sourceValue As New DataClass
sourceValue.DataMember = 5
ChildRoutine(sourceValue)
MsgBox(sourceValue.DataMember) ' --> Wyświetla 15
End Sub
Public Sub ChildRoutine(ByRef incoming As DataClass)
' ----- Poniższy wiersz zmienia  rzeczywistą składową.
incoming.DataMember = 10
' ----- Poniższe wiersze całkowicie zastępują egzemplarz wskazywany
' przez zmienną obiektową sourceValue.
incoming = New DataClass
incoming.DataMember = 15
End Sub
End Class
Stosowanie parametrów przekazywanych przez referencję łącznie z referencyjnymi typami
danych umożliwia procedurom docelowym zastępowanie oryginalnych obiektów zupełnie
nowymi egzemplarzami właściwych klas.
Argumenty opcjonalne
Język Visual Basic obsługuje parametry opcjonalne za pośrednictwem słowa kluczowego
Optional:
Sub Calculate(Optional ByVal silent As Boolean = False)
W przypadku wszystkich parametrów opcjonalnych ma zastosowanie następująca para reguł:
" Każda deklaracja argumentu opcjonalnego musi obejmować wartość domyślną, która do-
datkowo musi mieć postać wyrażenia stałego (w żadnym razie nie może być zmienną).
Wartość domyślna jest wykorzystywana tylko wtedy, gdy kod wywołujący nie dostarcza
argumentu dla parametru opcjonalnego.
" Każdy parametr zadeklarowany po parametrze opcjonalnym także musi być opcjonalny.
Oznacza to, że ewentualne parametry obowiązkowe (nieopcjonalne) muszą się znajdo-
wać na liście parametrów przed parametrami opcjonalnymi.
W wersjach Visual Basica sprzed wprowadzenia technologii .NET istniała możliwość rezygnacji
z wartości domyślnej i  jeśli typem parametru był Variant  stosowania funkcji IsMissing do
określania, czy odpowiednia wartość została przekazana. Opisane rozwiązanie nie jest obsłu-
giwane w platformie .NET, zatem dla wszystkich parametrów opcjonalnych koniecznie mu-
simy definiować wartości domyślne (na wypadek braku odpowiednich argumentów).
Tablice parametrów
W normalnych warunkach definicja procedury określa stałą liczbę parametrów. Programiści
Visual Basica mają jednak do dyspozycji słowo kluczowe ParamArray (od ang. parameter array 
tablica parametrów), za pośrednictwem którego można rozszerzać listę parametrów poza stały
zbiór elementów. Każde wywołanie tak zdefiniowanej procedury może zawierać inną liczbę
parametrów (oczywiście oprócz puli parametrów wymaganych).
Przeanalizujmy przykład funkcji wyznaczającej średnią ocenę z egzaminów, których liczba
nie jest znana (liczba ocen wejściowych w każdym wywołaniu może być inna):
Parametry i argumenty | 103
Public Function AverageScore(ByVal ParamArray scores( ) _
As Single) As Single
' ----- Oblicza średnią ocenę dla dowolnej liczby egzaminów.
Dim counter As Integer
AverageScore = 0
For counter = 0 To UBound(scores)
AverageScore += scores(counter)
Next counter
AverageScore /= UBound(scores) + 1
End Function
Wywołania funkcji AverageScore mogą teraz zawierać zróżnicowaną liczbę argumentów:
MsgBox(AverageScore(1, 2, 3, 4, 5)) ' --> Wyświetla 3
MsgBox(AverageScore(1, 2, 3)) ' --> Wyświetla 2
Poniżej przedstawiono reguły, które mają zastosowanie w przypadku parametrów deklarowa-
nych ze słowem kluczowym ParamArray:
" Procedura może otrzymywać na wejściu tylko jedną tablicę parametrów i ta tablica musi
być ostatnim elementem na liście parametrów.
" Tablica parametrów musi być przekazywana przez wartość, a jej deklaracja na liście para-
metrów procedury zawsze musi być opatrywana słowem kluczowym ByVal.
" Tablica parametrów musi być strukturą jednowymiarową. Jeśli nie zadeklarujemy jej typu,
kompilator automatycznie założy, że tablica składa się z elementów typu System.Object.
Tablica parametrów zawsze jest parametrem opcjonalnym. Jej domyślną wartością jest pusta
tablica jednowymiarowa właściwego typu danych.
104 | Rozdział 4. Zmienne i typy danych


Wyszukiwarka

Podobne podstrony:
Visual?sic 05 Od podstaw vb25po
Visual C 05 Express?ition Od podstaw cwvc25
Visual Studio 05 Programowanie z Windows API w jezyku C vs25pw
8 37 Skrypty w Visual Studio (2)
Wykład 05 Opadanie i fluidyzacja
Prezentacja MG 05 2012
2011 05 P
05 2
ei 05 08 s029
ei 05 s052

więcej podobnych podstron