Udostępnij za pomocą


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 IntegerInteger zamiast tablicy). Return AllOnes() Instrukcja generuje błąd kompilatora, ponieważ wydaje się AllOnes wywoływać 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 przekażesz ją według wartości.

  • Zmienna bazowa. Aby umożliwić procedurze zastąpienie wartości samego elementu zmiennej bazowej, 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. Jeśli zadeklarujesz parametr ByVal, procedura nie może zmodyfikować samego elementu zmiennej bazowej. Jeśli jednak argument jest typem odwołania, procedura może modyfikować 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 bazowej 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 jego 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

W poniższym przykładzie są wywoływane increase wywołania 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ładowe, 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 traci odwołanie do n przekazanego przez kod wywołujący. Gdy zwiększa ona elementy członkowskie aobiektu , ma to wpływ tylko na tablicę k lokalną.

Poprawne podejście: Aby móc zmodyfikować sam element zmiennej bazowej, przekaż go przy użyciu odwołania. W poniższym przykładzie pokazano zmianę w deklaracji replace , która umożliwia jej zastąpienie jednej tablicy innym 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 innego podpisu. 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 pozostałych składników podpisu. Aby uzyskać więcej informacji, zobacz Przeciążenie 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 (CType Operator) można różnić typ zwracany.

Rozpoznawanie przeciążenia przy użyciu argumentów opcjonalnych 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 procedur przeciążania.

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 rozwiązuje 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 poprawną liczbę argumentów i w odpowiedniej kolejności.
  • Najlepiej, aby argumenty miały dokładnie te same typy danych co odpowiednie parametry. W każdym razie typ danych każdego argumentu musi zostać rozszerzony do odpowiadającego mu parametru. Jest to prawdą nawet w przypadku ustawienia opcji Strict Statement ustawionej 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.

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

Niepowodzenie rozwiązywania przeciążenia

Podczas wywoływania przeciążonej procedury kompilator próbuje wyeliminować wszystkie, 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ążenia:

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 się do odpowiedniego typu 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 tej samej przyczyny 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ć procedurę przeciążoną 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ążenia przy użyciu argumentów opcjonalnych 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 drugim, kompilator rozpozna wywołanie tej procedury zgodnie z najbliższym dopasowaniem. Aby uzyskać więcej informacji, zobacz Rozpoznawanie przeciążenia.

Zobacz także