Перегрузка выполняется статически, поэтому, когда вы вызываете VisitImpl(t)
, компилятор должен выбрать единственный перегруженный метод, который представляет этот вызов (если он есть). Поскольку параметр типа T
может быть любым, единственный совместимый метод - это универсальный метод, и поэтому все вызовы из Visit<T>(T t)
вызывают в VisitImpl<T>(T t)
.
EDIT
Похоже, вы пришли из C ++, поэтому, возможно, стоит отметить, что шаблоны C ++ сильно отличаются от шаблонов C #; в частности, в C # нет такой вещи, как специализация, из-за которой поведение, которое вы видите, является неожиданным. Компилятор C # не генерирует разный код для разных типов, при которых может быть вызван универсальный метод (то есть компилятор C # вызывает тот же универсальный метод при вызове Visit(1)
и Visit("hello")
, это не генерирует специализации метода для типов int
и string
). Во время выполнения CLR создает специфичные для типа методы, но это происходит после компиляции и не может повлиять на разрешение перегрузки.
РЕДАКТИРОВАТЬ - еще более сложный
C # предпочитает неуниверсальные методы универсальным методам , когда статически известно, что неуниверсальный метод применим .
Компилятор C # выберет один метод для вызова на любом данном сайте вызова. Забудьте о полной перегрузке и присвойте своим методам разные имена; Какой из этих переименованных методов может быть вызван на данном сайте? Только общий. Поэтому, даже когда три имени сталкиваются и разрешается перегрузка, это единственная перегрузка, которая применима на этом сайте и является выбранным методом.