В последнее время я довольно много работал с провайдерами , и я столкнулся с интересной ситуацией, когда мне захотелось иметь абстрактный класс с абстрактным статическим методом. Я прочитал несколько сообщений на эту тему, и это вроде как имело смысл, но есть ли хорошее четкое объяснение?
c#
.net
language-design
lomaxx
источник
источник
Ответы:
Статические методы не создаются как таковые, они просто доступны без ссылки на объект.
Вызов статического метода выполняется через имя класса, а не через ссылку на объект, и код Intermediate Language (IL) для его вызова вызовет абстрактный метод через имя класса, который его определил, а не обязательно имя класс, который вы использовали.
Позвольте мне показать пример.
Со следующим кодом:
Если вы звоните B.Test, вот так:
Тогда фактический код внутри метода Main выглядит следующим образом:
Как видите, вызов сделан в A.Test, потому что его определил класс A, а не B.Test, даже если вы можете написать код таким способом.
Если у вас были типы классов , как в Delphi, где вы можете создать переменную, ссылающуюся на тип, а не на объект, вы бы больше использовали виртуальные и, следовательно, абстрактные статические методы (а также конструкторы), но они недоступны и таким образом, статические вызовы не являются виртуальными в .NET.
Я понимаю, что конструкторы IL могут позволить скомпилировать код для вызова B.Test и разрешить вызов во время выполнения, но он все равно не будет виртуальным, так как вам все равно придется написать какое-то имя класса.
Виртуальные методы и, следовательно, абстрактные, полезны только в том случае, если вы используете переменную, которая во время выполнения может содержать множество различных типов объектов, и, таким образом, вы хотите вызвать правильный метод для текущего объекта, который у вас есть в переменной. Со статическими методами вам все равно нужно пройти через имя класса, поэтому точный метод для вызова известен во время компиляции, потому что он не может и не будет меняться.
Таким образом, виртуальные / абстрактные статические методы не доступны в .NET.
источник
Test()
вA
а не абстрактным и потенциально определены вB
\.Car
тип с виртуальным статическимCreateFromDescription
фабричным методом, то код, который принимаетCar
обобщенный тип -ограниченный,T
может вызватьT.CreateFromDescription
автомобиль типаT
. Такая конструкция вполне могла бы поддерживаться в CLR, если бы каждый тип, который определил такой метод, содержал статический одноэлементный экземпляр универсального вложенного класса, который содержал виртуальные «статические» методы.Статические методы не могут быть унаследованы или переопределены, и поэтому они не могут быть абстрактными. Поскольку статические методы определены для типа, а не для экземпляра класса, они должны вызываться явно для этого типа. Поэтому, когда вы хотите вызвать метод в дочернем классе, вам нужно использовать его имя для его вызова. Это делает наследство неактуальным.
Предположим, вы могли бы на мгновение наследовать статические методы. Представьте себе этот сценарий:
Если вы вызываете Base.GetNumber (), какой метод будет вызван? Какое значение вернулось? Довольно легко увидеть, что без создания экземпляров объектов наследование довольно сложно. Абстрактные методы без наследования - это просто методы, которые не имеют тела, поэтому не могут быть вызваны.
источник
int DoSomething<T>() where T:Base {return T.GetNumber();}
. Казалось бы, полезно былоDoSomething<Base>()
бы вернуть пять, аDoSomething<Child2>()
вернуло бы два. Такая способность была бы полезна не только для примеров игрушек, но и для чего-то подобногоclass Car {public static virtual Car Build(PurchaseOrder PO);}
, где каждый производный классCar
должен был бы определить метод, который мог бы создать экземпляр с учетом заказа на покупку.Другой респондент (Макдауэлл) сказал, что полиморфизм работает только для экземпляров объектов. Это должно быть квалифицировано; Существуют языки, которые рассматривают классы как экземпляры типа «Класс» или «Метакласс». Эти языки поддерживают полиморфизм как для экземпляров, так и для классов (статических) методов.
C #, как и Java и C ++ до него, не является таким языком;
static
ключевое слово используется для обозначения явно , что метод статический переплетом , а не динамический / виртуальный.источник
Вот ситуация, когда существует определенная необходимость наследования для статических полей и методов:
источник
legs
должно быть статическим абстрактным свойством.Чтобы добавить к предыдущим объяснениям, вызовы статических методов привязываются к определенному методу во время компиляции , что скорее исключает полиморфное поведение.
источник
Мы на самом деле переопределяем статические методы (в delphi), это немного уродливо, но прекрасно работает для наших нужд.
Мы используем его, чтобы у классов был список доступных объектов без экземпляра класса, например, у нас есть метод, который выглядит следующим образом:
Это некрасиво, но необходимо, так как мы можем создавать именно то, что нужно, вместо того, чтобы создавать все классы только для поиска доступных объектов.
Это был простой пример, но само приложение является клиент-серверным приложением, в котором все классы доступны только на одном сервере, и несколько разных клиентов, которым может не понадобиться все, что есть на сервере, и никогда не понадобится экземпляр объекта.
Так что это гораздо проще поддерживать, чем иметь одно отдельное серверное приложение для каждого клиента.
Надеюсь, пример был ясен.
источник
Абстрактные методы неявно виртуальны. Абстрактные методы требуют экземпляра, но статические методы не имеют экземпляра. Таким образом, вы можете иметь статический метод в абстрактном классе, он просто не может быть статическим абстрактным (или абстрактным статическим).
источник