2010-11-17 16 views

Odpowiedz

4

Możesz śledzić te proste zasady, jeden po drugim, aby ustalić, które należy użyć:

  • jest metoda static? Następnie użyj call.
  • Czy typ wywołujesz dla typu wartości? Następnie użyj call. (Ten nie ma zastosowania, jeżeli wartość jest zapakowane - wtedy faktycznie powołując się na object lub jakiś interfejs, a te są typy referencyjne.)
  • Czy jesteś Wywoływanie metody zadeklarowane virtual lub abstract? Następnie użyj callvirt.
  • Czy wywołujesz metodę poprzez odwołanie do interfejsu? Następnie użyj callvirt.
  • Czy wywoływana metoda jest zadeklarowana jako override, ale ani metoda, ani zadeklarowany typ nie został zadeklarowany jako sealed? Następnie użyj callvirt.

We wszystkich innych przypadkach, nie wirtualnym sklepie jest wymagana, więc może używać call - ale powinien użycie callvirt. Oto dlaczego:

Używanie metod innych niż wirtualne jest jednoznaczne z call, chyba że pierwszy argument ma wartość null. W takim przypadku callvirt natychmiast wyrzuci NullReferenceException, natomiast call nie. Ma to sens, ponieważ callvirt jest przeznaczony do użycia w przypadkach, gdy pożądane jest wysyłanie metod wirtualnych i nie można przeprowadzić wirtualnej wysyłki metod, jeśli nie masz obiektu, na którym można wykonać wyszukiwanie w tabeli.

Należy pamiętać, że callvirt będzie nadal zgłaszał wyjątek, jeśli pierwszy argument ma wartość null, nawet jeśli nie jest konieczne wyszukiwanie wzorca!

Biorąc pod uwagę te informacje, korzystając callvirt dla wszystkich metod non-statycznych wywołań dotyczących typów referencyjnych (jak kompilator C# nie) może być korzystne, ponieważ będzie ona powodować NullReferenceException natychmiast w miejscu połączenia zamiast jakiś czas później, kiedy this przyzwyczaja (jawnie lub niejawnie) wewnątrz metody.

+0

Ale .NET używa "wywołania" podczas wywoływania czegoś takiego jak Point.X. Z tego co czytam najwyraźniej metody typu wartości korzystają z "połączenia". – Will

+2

Tak, ponieważ te metody nie są wirtualne, więc oczekiwałbym, że wyjście użyje "wywołania". Przeczytaj ponownie moją odpowiedź. (Ponadto, struktury * nie mogą * mieć wirtualnych członków, ponieważ nie mogą być dziedziczone). – cdhowie

+0

To ma sens, dzięki. Dziwne, że ta refleksja pokazuje "IsVirtual" jako prawdziwe dla metod struktury. – Will

6

Domyślnie kompilator C# zawsze używa callvirt dla wszystkiego oprócz wywołań typu static lub value. Powoduje to niejawne sprawdzanie wartości "this" (arg0). Nie musisz ściśle przestrzegać tej konwencji, ale każda wirtualna metoda na typie referencyjnym z pewnością będzie wymagać callvirt.

+1

Z wyjątkiem metod wirtualnych na zamkniętych klasach. –

0

Jeśli używasz wywołania w metodzie dynamicznej w metodzie wirtualnej, środowisko wykonawcze zgłasza wyjątek bezpieczeństwa.