Udostępnij za pośrednictwem


Procedury rozwiązywania problemów (Visual Basic)

Na tej stronie wymieniono niektóre typowe problemy, które mogą wystąpić podczas pracy z procedurami.

Zwracanie typu tablicy z procedury funkcji

Function Jeśli procedura zwraca typ danych tablicy, nie można użyć Function nazwy do przechowywania wartości w elementach tablicy. Jeśli spróbujesz to zrobić, kompilator interpretuje go jako wywołanie metody Function. Poniższy przykład generuje błędy kompilatora:

Function AllOnes(n As Integer) As Integer()
   For i As Integer = 1 To n - 1  
      ' The following statement generates a COMPILER ERROR.  
      AllOnes(i) = 1  
   Next  

   ' The following statement generates a COMPILER ERROR.  
   Return AllOnes()  
End Function

AllOnes(i) = 1 Instrukcja generuje błąd kompilatora, ponieważ wydaje się, że wywołuje AllOnes argument nieprawidłowego typu danych (skalarny Integer zamiast Integer tablicy). Return AllOnes() Instrukcja generuje błąd kompilatora, ponieważ wydaje się, że jest wywoływany AllOnes bez argumentu.

Poprawne podejście: Aby móc modyfikować elementy tablicy, które mają być zwracane, zdefiniuj tablicę wewnętrzną jako zmienną lokalną. Poniższy przykład kompiluje się bez błędu:

Function AllOnes(n As Integer) As Integer()
    Dim iArray(n - 1) As Integer
    For i = 0 To n - 1
        iArray(i) = 1
    Next
    Return iArray
End Function

Argument nie został zmodyfikowany przez wywołanie procedury

Jeśli zamierzasz zezwolić procedurze na zmianę elementu programowania bazowego argumentu w kodzie wywołującym, musisz przekazać go przy użyciu odwołania. Jednak procedura może uzyskać dostęp do elementów argumentu typu odwołania, nawet jeśli zostanie przekazana przez wartość.

  • Zmienna bazowa. Aby umożliwić procedurze zastąpienie wartości bazowego elementu zmiennej, procedura musi zadeklarować parametr ByRef. Ponadto kod wywołujący nie może ująć argumentu w nawiasach, ponieważ spowoduje to zastąpienie ByRef mechanizmu przekazywania.

  • Elementy typu odwołania. W przypadku zadeklarowania parametru ByVal procedura nie może zmodyfikować samego bazowego elementu zmiennej. Jeśli jednak argument jest typem odwołania, procedura może zmodyfikować elementy członkowskie obiektu, do którego wskazuje, mimo że nie może zastąpić wartości zmiennej. Jeśli na przykład argument jest zmienną tablicową, procedura nie może przypisać do niej nowej tablicy, ale może zmienić jeden lub więcej elementów. Zmienione elementy są odzwierciedlane w podstawowej zmiennej tablicowej w kodzie wywołującym.

W poniższym przykładzie zdefiniowano dwie procedury, które przyjmują zmienną tablicową według wartości i działają na jej elementach. Procedura increase po prostu dodaje jeden do każdego elementu. Procedura replace przypisuje nową tablicę do parametru a() , a następnie dodaje jedną do każdego elementu. Jednak ponowne przypisanie nie ma wpływu na podstawową zmienną tablicową w kodzie wywołującym, ponieważ a() jest zadeklarowana ByVal.

Public Sub increase(ByVal a() As Long)
    For j As Integer = 0 To UBound(a)
        a(j) = a(j) + 1
    Next j
End Sub
Public Sub replace(ByVal a() As Long)
    Dim k() As Long = {100, 200, 300}
    a = k
    For j As Integer = 0 To UBound(a)
        a(j) = a(j) + 1
    Next j
End Sub

Poniższy przykład wykonuje wywołania metod increase i replace:

Dim n() As Long = {10, 20, 30, 40}
Call increase(n)
MsgBox("After increase(n): " & CStr(n(0)) & ", " & 
    CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
Call replace(n)
MsgBox("After replace(n): " & CStr(n(0)) & ", " & 
    CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))

MsgBox Pierwsze wywołanie wyświetla komunikat "After increase(n): 11, 21, 31, 41". Ponieważ n jest typem odwołania, increase może zmienić jego składowych, mimo że jest przekazywany ByVal.

Drugie MsgBox wywołanie wyświetla komunikat "After replace(n): 11, 21, 31, 41". Ponieważ n jest przekazywana ByVal, replace nie można zmodyfikować zmiennej n , przypisując do niej nową tablicę. Podczas replace tworzenia nowego wystąpienia k tablicy i przypisywania go do zmiennej alokalnej powoduje utratę odwołania do n przekazanego przez kod wywołujący. Gdy zwiększa ona elementy członkowskie obiektu a, ma to wpływ tylko na tablicę k lokalną.

Poprawne podejście: Aby móc zmodyfikować sam element zmiennej bazowej, przekaż go za pomocą odwołania. W poniższym przykładzie pokazano zmianę deklaracji replace , która umożliwia zastąpienie jednej tablicy inną w kodzie wywołującym:

Public Sub replace(ByRef a() As Long)

Nie można zdefiniować przeciążenia

Jeśli chcesz zdefiniować przeciążoną wersję procedury, musisz użyć tej samej nazwy, ale innej sygnatury. Jeśli kompilator nie może odróżnić deklaracji od przeciążenia z tym samym podpisem, generuje błąd.

Podpis procedury jest określany przez nazwę procedury i listę parametrów. Każde przeciążenie musi mieć taką samą nazwę jak wszystkie inne przeciążenia, ale musi się różnić od wszystkich z nich w co najmniej jednym z innych składników podpisu. Aby uzyskać więcej informacji, zobacz Przeciążanie procedury.

Następujące elementy, mimo że odnoszą się one do listy parametrów, nie są składnikami podpisu procedury:

  • Słowa kluczowe modyfikatora procedury, takie jak Public, Sharedi Static.
  • Nazwy parametrów.
  • Słowa kluczowe modyfikatora parametrów, takie jak ByRef i Optional.
  • Typ danych zwracanej wartości (z wyjątkiem operatora konwersji).

Nie można przeciążyć procedury, zmieniając tylko jeden lub więcej powyższych elementów.

Poprawne podejście: Aby można było zdefiniować przeciążenie procedury, należy zmienić podpis. Ponieważ musisz użyć tej samej nazwy, musisz różnić liczbę, kolejność lub typy danych parametrów. W procedurze ogólnej można różnić liczbę parametrów typu. W operatorze konwersji (funkcja CType) można różnić typ zwracany.

Rozpoznawanie przeciążeń za pomocą argumentów Optional i ParamArray

Jeśli przeciążasz procedurę z co najmniej jednym parametrem opcjonalnym lub parametrem ParamArray , należy unikać duplikowania dowolnych niejawnych przeciążeń. Aby uzyskać informacje, zobacz Zagadnienia dotyczące przeciążania procedur.

Wywoływanie nieprawidłowej wersji procedury przeciążonej

Jeśli procedura ma kilka przeciążonych wersji, należy zapoznać się ze wszystkimi ich listami parametrów i zrozumieć, jak język Visual Basic rozpoznaje wywołania między przeciążeniami. W przeciwnym razie można wywołać przeciążenie inne niż zamierzone.

Po określeniu, które przeciążenie chcesz wywołać, należy zachować ostrożność, aby przestrzegać następujących reguł:

  • Podaj prawidłową liczbę argumentów i w prawidłowej kolejności.
  • Najlepiej, aby argumenty miały dokładnie te same typy danych co odpowiednie parametry. W każdym przypadku typ danych każdego argumentu musi być rozszerzony do odpowiadającego mu parametru. Jest to prawdą nawet w przypadku ustawienia Opcji Strict Statement ustawionego na Offwartość . Jeśli przeciążenie wymaga konwersji zawężającej z listy argumentów, to przeciążenie nie kwalifikuje się do wywołania.
  • Jeśli podasz argumenty, które wymagają rozszerzenia, ustaw ich typy danych tak blisko, jak to możliwe do odpowiednich typów danych parametrów. Jeśli co najmniej dwa przeciążenia akceptują typy danych argumentów, kompilator rozwiąże wywołanie przeciążenia, które wywołuje najmniejszą ilość rozszerzania.

Możesz zmniejszyć prawdopodobieństwo niezgodności typów danych przy użyciu słowa kluczowego konwersji funkcji CType podczas przygotowywania argumentów.

Niepowodzenie rozwiązywania przeciążenia

Podczas wywoływania przeciążonej procedury kompilator próbuje wyeliminować wszystkie z nich, ale jedno z przeciążeń. Jeśli to się powiedzie, rozwiąże wywołanie tego przeciążenia. Jeśli eliminuje wszystkie przeciążenia lub jeśli nie może zmniejszyć kwalifikujących się przeciążeń do jednego kandydata, generuje błąd.

Poniższy przykład ilustruje proces rozwiązywania przeciążeń:

Overloads Sub z(ByVal x As Byte, ByVal y As Double)
End Sub
Overloads Sub z(ByVal x As Short, ByVal y As Single)
End Sub
Overloads Sub z(ByVal x As Integer, ByVal y As Single)
End Sub
Dim r, s As Short
Call z(r, s)
Dim p As Byte, q As Short
' The following statement causes an overload resolution error.
Call z(p, q)

W pierwszym wywołaniu kompilator eliminuje pierwsze przeciążenie, ponieważ typ pierwszego argumentu (Short) zawęża typ odpowiedniego parametru (Byte). Następnie eliminuje trzecie przeciążenie, ponieważ każdy typ argumentu w drugim przeciążeniu (Short i Single) rozszerza odpowiedni typ w trzecim przeciążeniu (Integer i Single). Drugie przeciążenie wymaga mniejszego rozszerzenia, więc kompilator używa go do wywołania .

W drugim wywołaniu kompilator nie może wyeliminować żadnego z przeciążeń na podstawie zawężenia. Eliminuje trzecie przeciążenie z tego samego powodu, co w pierwszym wywołaniu, ponieważ może wywołać drugie przeciążenie z mniejszym rozszerzaniem typów argumentów. Jednak kompilator nie może rozpoznać między pierwszym i drugim przeciążeniami. Każdy z nich ma jeden zdefiniowany typ parametru, który rozszerza odpowiedni typ w drugim (Byte do Short, ale Single do Double). W związku z tym kompilator generuje błąd rozwiązywania przeciążenia.

Poprawne podejście: Aby móc wywołać przeciążonej procedury bez niejednoznaczności, użyj funkcji CType , aby dopasować typy danych argumentów do typów parametrów. W poniższym przykładzie pokazano wywołanie, z które wymusza rozwiązanie drugiego przeciążenia.

Call z(CType(p, Short), CType(q, Single))

Rozpoznawanie przeciążeń za pomocą argumentów Optional i ParamArray

Jeśli dwa przeciążenia procedury mają identyczne podpisy, z tą różnicą, że ostatni parametr jest zadeklarowany jako Opcjonalny w jednym i ParamArray w drugiej, kompilator rozwiązuje wywołanie tej procedury zgodnie z najbliższym dopasowaniem. Aby uzyskać więcej informacji, zobacz Rozpoznawanie przeciążenia.

Zobacz też