Алгоритм основан на поиске маршрута между двумя точками, а другой проверяет, могут ли все точки быть связаны (имея маршрут между ними):
Just playing safe.
Technically C# compiler doesn't always use callvirt
For static methods & methods defined on value types, it uses call
. The majority is provided via the callvirt
IL instruction.
The difference that swung the vote between the two is the fact that call
assumes the "object being used to make the call" is not null. callvirt
on the other hand checks for not null and throws a NullReferenceException if required.
call
is used for them - better performance.callvirt
so the JIT compiler verifies that the object being used to make the call is not null. Even for non-virtual instance methods.. they valued safety over performance.See Also: Jeff Richter does a better job at this - in his 'Designing Types' chapter in CLR via C# 2nd Ed
См. это старое сообщение в блоге Эрика Ганнерсона.
Вот текст сообщения:
Почему C # всегда использует callvirt?
Этот вопрос придумал внутренний псевдоним C #, и я подумал, что ответ будет представлять общий интерес. Это при условии, что ответ правильный - прошло уже довольно много времени.
Язык .NET IL предоставляет как команду call, так и callvirt, причем callvirt используется для вызова виртуальных функций. Но если вы посмотрите код, который генерирует C #, вы увидите, что он генерирует «callvirt» даже в тех случаях, когда не задействована виртуальная функция. Почему он это делает?
Я просмотрел имеющиеся у меня заметки по языковому дизайну, и в них довольно четко указано, что мы решили использовать callvirt 13.12.1999. К сожалению, они не Я уловил наше обоснование для этого, так что мне придется обратиться к моей памяти.
Мы получили отчет от кого-то (вероятно, одной из групп .NET, использующих C # (думали, что это еще не было названо C # в то время)), которые написали код, который вызывал метод по нулевому указателю, но они не получили исключения, потому что метод не обращался к каким-либо полям (т.е. «this» было пустым, но ничто в методе не использовало его ). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.
Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
m придется уйти из моей памяти.Мы получили отчет от кого-то (вероятно, одной из групп .NET, использующих C # (думала, что это еще не было C # в то время)), кто написал код, который вызывал метод с нулевым указателем, но они не получили исключения, потому что метод не имел доступа ни к каким полям (т.е. «this» было пустым, но ничто в методе его не использовало). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.
Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
m придется уйти из моей памяти.Мы получили отчет от кого-то (вероятно, одной из групп .NET, использующих C # (думала, что это еще не было C # в то время)), кто написал код, который вызывал метод с нулевым указателем, но они не получили исключения, потому что метод не имел доступа ни к каким полям (т.е. «this» было пустым, но ничто в методе его не использовало). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.
Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
Мы получили отчет от кого-то (вероятно, одной из групп .NET, использующих C # (думали, что это еще не было C # в то время)), кто написал код, который вызывал метод по нулевому указателю, но они этого не сделали. не получить исключения, потому что метод не обращался ни к каким полям (т.е. «this» было пустым, но ничто в методе его не использовало). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.
Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
Мы получили отчет от кого-то (вероятно, одной из групп .NET, использующих C # (думали, что это еще не было C # в то время)), кто написал код, который вызывал метод по нулевому указателю, но они этого не сделали. не получить исключения, потому что метод не обращался ни к каким полям (т.е. «this» было пустым, но ничто в методе его не использовало). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.
Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
t в то время еще назывался C #)), которые написали код, который вызывал метод по нулевому указателю, но они не получили исключения, потому что метод не обращался ни к каким полям (т.е. «this» было пустым, но ничего в метод использовал это). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
t в то время еще назывался C #)), которые написали код, который вызывал метод по нулевому указателю, но они не получили исключения, потому что метод не обращался ни к каким полям (т.е. «this» было пустым, но ничего в метод использовал это). Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
Затем этот метод вызвал другой метод, который действительно использовал точку this и вызвал исключение, что привело к некоторой головной боли. После того, как они это выяснили, они прислали нам сообщение об этом.Мы думали, что возможность вызвать метод для нулевого экземпляра была немного странной. Питер Голд провел некоторое тестирование, чтобы увидеть, какое влияние на производительность оказывает постоянное использование callvirt, и оно было достаточно небольшим, чтобы мы решили внести изменения.
В качестве (возможно-) интересного в сторону ... GetType ()
необычен тем, что не виртуальный
- это приводит к некоторым очень и очень странным вещам .
(помечено как wiki, поскольку это несколько не по теме фактического вопроса)
Компилятору неизвестен реальный тип o
в первом выражении, но он знает реальный тип во втором выражении. Похоже, он просматривает только один оператор за раз.
Это нормально, потому что C # сильно зависит от JIT для оптимизации. Весьма вероятно, что в таком простом случае оба вызова станут вызовами экземпляра во время выполнения.
Я не верю, что callvirt
когда-либо испускается для невиртуальных методов, но даже если бы это было так, он бы не будет проблемой, потому что метод никогда не будет отменен (по очевидным причинам).
Я рискну предположить, что это потому, что первое присваивается переменной, которая потенциально может содержать экземпляр другого типа с пониженным преобразованием, который мог бы переопределить GetType
(хотя мы видим, что это не так); второй никогда не мог быть ничем иным, кроме Объект
.