Почему у меня не может быть абстрактных статических методов в C #?

StackOverflow https://stackoverflow.com/questions/3284

  •  08-06-2019
  •  | 
  •  

Вопрос

Я работал с поставщики услуг совсем недавно я столкнулся с интересной ситуацией, когда мне захотелось создать абстрактный класс с абстрактным статическим методом.Я прочитал несколько постов на эту тему, и это вроде бы имело смысл, но есть ли хорошее четкое объяснение?

Это было полезно?

Решение

Статические методы не являются созданный экземпляр как таковые, они просто доступны без ссылки на объект.

Вызов статического метода выполняется через имя класса, а не через ссылку на объект, и код промежуточного языка (IL) для его вызова вызовет абстрактный метод через имя класса, который его определил, не обязательно имя класса, который вы использовали.

Позвольте мне показать пример.

Со следующим кодом:

public class A
{
    public static void Test()
    {
    }
}

public class B : A
{
}

Если вы вызовете B.Test, вот так:

class Program
{
    static void Main(string[] args)
    {
        B.Test();
    }
}

Тогда фактический код внутри основного метода выглядит следующим образом:

.entrypoint
.maxstack 8
L0000: nop 
L0001: call void ConsoleApplication1.A::Test()
L0006: nop 
L0007: ret 

Как вы можете видеть, вызов выполняется для A.Test, потому что именно класс A определил его, а не для B.Test , хотя вы можете написать код таким образом.

Если бы у вас было типы классов, как и в Delphi, где вы можете создать переменную, ссылающуюся на тип, а не на объект, вы могли бы больше использовать виртуальные и, следовательно, абстрактные статические методы (а также конструкторы), но они недоступны, и, следовательно, статические вызовы в .NET невиртуальны.

Я понимаю, что разработчики IL могли бы разрешить компиляцию кода для вызова B.Test и разрешить вызов во время выполнения, но он все равно не был бы виртуальным, так как вам все равно пришлось бы написать там какое-то имя класса.

Виртуальные методы и, следовательно, абстрактные методы полезны только тогда, когда вы используете переменную, которая во время выполнения может содержать много различных типов объектов, и поэтому вы хотите вызвать правильный метод для текущего объекта, который у вас есть в переменной.Со статическими методами вам все равно нужно пройти через имя класса, поэтому точный метод для вызова известен во время компиляции, потому что он не может и не будет меняться.

Таким образом, виртуальные / абстрактные статические методы недоступны в .NET.

Другие советы

Статические методы не могут быть унаследованы или переопределены, и именно поэтому они не могут быть абстрактными.Поскольку статические методы определены для типа, а не для экземпляра класса, они должны вызываться явно для этого типа.Поэтому, когда вы хотите вызвать метод в дочернем классе, вам нужно использовать его имя для его вызова.Это делает наследование неуместным.

Предположим, на мгновение вы могли бы наследовать статические методы.Представьте себе такой сценарий:

public static class Base
{
    public static virtual int GetNumber() { return 5; }
}

public static class Child1 : Base
{
    public static override int GetNumber() { return 1; }
}

public static class Child2 : Base
{
    public static override int GetNumber() { return 2; }
}

Если вы вызовете Base.getNumber(), какой метод будет вызван?Какое возвращаемое значение?Довольно легко увидеть, что без создания экземпляров объектов наследование довольно сложно.Абстрактные методы без наследования - это просто методы, которые не имеют тела, поэтому не могут быть вызваны.

Другой респондент (Макдауэлл) сказал, что полиморфизм работает только для экземпляров объектов.Это должно быть оговорено;существуют языки, которые рассматривают классы как экземпляры типа "Класс" или "Метакласс".Эти языки поддерживают полиморфизм как для методов экземпляра, так и для методов класса (статических).

C #, как и Java и C ++ до него, таким языком не является;тот самый static ключевое слово используется явно для обозначения того, что метод является статически привязанным, а не динамическим / виртуальным.

В дополнение к предыдущим объяснениям, вызовы статических методов привязаны к определенному методу в время компиляции, что скорее исключает полиморфное поведение.

Вот ситуация, когда определенно существует необходимость в наследовании статических полей и методов:

abstract class Animal
{
  protected static string[] legs;

  static Animal() {
    legs=new string[0];
  }

  public static void printLegs()
  {
    foreach (string leg in legs) {
      print(leg);
    }
  }
}


class Human: Animal
{
  static Human() {
    legs=new string[] {"left leg", "right leg"};
  }
}


class Dog: Animal
{
  static Dog() {
    legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
  }
}


public static void main() {
  Dog.printLegs();
  Human.printLegs();
}


//what is the output?
//does each subclass get its own copy of the array "legs"?

На самом деле мы переопределяем статические методы (в delphi), это немного некрасиво, но для наших нужд работает просто отлично.

Мы используем его, чтобы классы могли иметь список своих доступных объектов без экземпляра класса, например, у нас есть метод, который выглядит следующим образом:

class function AvailableObjects: string; override;
begin
  Result := 'Object1, Object2';
end; 

Это некрасиво, но необходимо, таким образом, мы можем создавать экземпляры только того, что необходимо, вместо того, чтобы создавать экземпляры всех классов только для поиска доступных объектов.

Это был простой пример, но само приложение представляет собой клиент-серверное приложение, которое имеет все классы, доступные только на одном сервере, и несколько разных клиентов, которым может не понадобиться все, что есть на сервере, и которым никогда не понадобится экземпляр объекта.

Таким образом, это намного проще в обслуживании, чем иметь одно отдельное серверное приложение для каждого клиента.

Надеюсь, пример был ясен.

Абстрактные методы неявно являются виртуальными.Абстрактные методы требуют экземпляра, но статические методы не имеют экземпляра.Итак, у вас может быть статический метод в абстрактном классе, он просто не может быть статическим абстрактным (или abstract static абстрактным статическим).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top