Jak ustalić, czy należy wywołać metodę za pomocą "Call" lub "Callvirt"?.NET CIL Call lub CallVirt?
Odpowiedz
Możesz śledzić te proste zasady, jeden po drugim, aby ustalić, które należy użyć:
- jest metoda
static
? Następnie użyjcall
. - 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ę naobject
lub jakiś interfejs, a te są typy referencyjne.) - Czy jesteś Wywoływanie metody zadeklarowane
virtual
lubabstract
? Następnie użyjcallvirt
. - 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 jakosealed
? Następnie użyjcallvirt
.
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.
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
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
To ma sens, dzięki. Dziwne, że ta refleksja pokazuje "IsVirtual" jako prawdziwe dla metod struktury. – Will
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.
Z wyjątkiem metod wirtualnych na zamkniętych klasach. –
Jeśli używasz wywołania w metodzie dynamicznej w metodzie wirtualnej, środowisko wykonawcze zgłasza wyjątek bezpieczeństwa.
Co to ma wspólnego z C#? – SLaks