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

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

Комментарии к вопросу (6)
Решение

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

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

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

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

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

public class B : A
{
}

Если вы вызовете B.Test следующим образом:

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

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

.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.

Комментарии (3)

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

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

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(), какой метод будет вызван? Какое значение будет возвращено? Легко понять, что без создания экземпляров объектов наследование довольно затруднительно. Абстрактные методы без наследования - это просто методы, которые не имеют тела, поэтому не могут быть вызваны.

Комментарии (5)

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

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

Комментарии (0)

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

Комментарии (6)

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

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"?
Комментарии (3)

Мы на самом деле отвергаем статические методы (в Дельфи), it' s немного ужасный, но это работает просто великолепно для наших потребностей.

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

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

It' s ужасный, но необходимый, этот способ, которым мы можем иллюстрировать примерами, что необходимо, вместо того, чтобы иметь все классы instantianted только, чтобы искать доступные объекты.

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

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

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

Комментарии (0)

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

Комментарии (1)