Подтвердить что ты не робот

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

У меня есть вспомогательный класс, который представляет собой всего лишь кучу статических методов и хотел бы подклассифицировать вспомогательный класс. Некоторое поведение уникально в зависимости от подкласса, поэтому я хотел бы вызвать виртуальный метод из базового класса, но поскольку все методы являются статичными, я не могу создать простой виртуальный метод (нужна ссылка на объект для доступа к виртуальному методу).

Есть ли способ обойти это? Я думаю, я мог бы использовать одноэлементный. HelperClass.Instance.HelperMethod() не намного хуже, чем HelperClass.HelperMethod(). Брауни указывает на тех, кто может указать некоторые языки, поддерживающие виртуальные статические методы.

Изменить: Хорошо, да, я сумасшедший. Результаты поиска Google заставили меня подумать, что я не был там немного.

4b9b3361

Ответ 1

Виртуальные статические методы не имеют смысла. Если я вызываю HelperClass.HelperMethod();, почему я должен ожидать, что будет вызван метод случайного подкласса? Решение действительно ломается, когда у вас есть 2 подкласса HelperClass - который вы бы использовали?

Если вы хотите иметь переопределяемые методы статического типа, вы должны, вероятно, пойти с:

  • Синглтон, если вы хотите, чтобы один и тот же подкласс использовался глобально.
  • Иерархия классов традиций с инъекцией factory или зависимости, если вы хотите различное поведение в разных частях вашего приложения.

Выберите, какое решение имеет больше смысла в вашей ситуации.

Ответ 2

Я не думаю, что ты сумасшедший. Вы просто хотите использовать то, что невозможно в .NET. Ваш запрос на виртуальный статический метод имел бы такой смысл, если мы говорим о дженериках. Например, мой будущий запрос дизайнеров CLR должен позволить мне написать intereface следующим образом:

public interface ISumable<T>
{
  static T Add(T left, T right);
}

и используйте его следующим образом:

public T Aggregate<T>(T left, T right) where T : ISumable<T>
{
  return T.Add(left, right);
}

Но это невозможно сейчас, поэтому я делаю это вот так:

    public static class Static<T> where T : new()
    {
      public static T Value = new T();
    }

    public interface ISumable<T>
    {
      T Add(T left, T right);
    }

    public T Aggregate<T>(T left, T right) where T : ISumable<T>, new()
    {
      return Static<T>.Value.Add(left, right);
    }

Ответ 3

Действительно, это можно сделать в Delphi. Пример:

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  end;

  TTestClass = class
  public
    class procedure TestMethod(); virtual;
  end;

  TTestDerivedClass = class(TTestClass)
  public
    class procedure TestMethod(); override;
  end;

  TTestMetaClass = class of TTestClass;

var
  Form1: TForm1;

implementation

{$R *.dfm}

class procedure TTestClass.TestMethod();
begin
  Application.MessageBox('base', 'Message');
end;

class procedure TTestDerivedClass.TestMethod();
begin
  Application.MessageBox('descendant', 'Message');
end;


procedure TForm1.FormShow(Sender: TObject);
var
  sample: TTestMetaClass;
begin
  sample := TTestClass;
  sample.TestMethod;
  sample := TTestDerivedClass;
  sample.TestMethod;
end;

Довольно интересно. Я больше не использую Delphi, но вспоминаю возможность очень легко создавать различные типы элементов управления на пользовательском холсте дизайнера, используя функцию метакласса: например, класс элемента управления. TButton, TTextBox и т.д. Были параметром, и я мог вызвать соответствующий конструктор, используя фактический аргумент метакласса.

Вид бедного человека фабричного образца :)

Ответ 4

Вы можете добиться такого же эффекта, просто используя обычный статический метод, а затем затеняйте его ключевым словом new

public class Base 
{
    //Other stuff

    public static void DoSomething()
    {
        Console.WriteLine("Base");
    }
}

public class SomeClass : Base
{
    public new static void DoSomething()
    {
        Console.WriteLine("SomeClass");
    }
}
public class SomeOtherClass : Base
{
}

Затем вы можете вызвать такие методы

Base.DoSomething(); //Base
SomeClass.DoSomething(); //SomeClass
SomeOtherClass.DoSomething(); //Base

Ответ 5

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

    class Root {
       public static virtual string TestMethod() {return "Root"; }
    }
    TRootClass = class of TRoot; // Here is the typed type declaration

    class Derived : Root {
       public static overide string TestMethod(){ return "derived"; }
    }

   class Test {
        public static string Run(){
           TRootClass rc;
           rc = Root;
           Test(rc);
           rc = Derived();
           Test(rc);
        }
        public static Test(TRootClass AClass){
           string str = AClass.TestMethod();
           Console.WriteLine(str);
        }
    } 

будет производить: корень полученный

Ответ 6

статический метод существует вне экземпляра класса. Он не может использовать нестатические данные.

виртуальный метод будет "перезаписан" перегруженной функцией в зависимости от типа экземпляра.

поэтому у вас есть явное противоречие между статическим и виртуальным.

Это не проблема поддержки, это концепция.

Обновление: Я оказался здесь неправым (см. комментарии):

Поэтому я сомневаюсь, что вы найдете любой OOP-язык, который будет поддерживать виртуальный статические методы.

Ответ 8

Я слышал, что Delphi утверждает что-то вроде этого. Кажется, он делает это, создавая экземпляры объектов класса метакласса.

Я не видел, чтобы он работал, поэтому я не уверен, что он работает, или в чем смысл этого.

P.S. Пожалуйста, поправьте меня, если я ошибаюсь, поскольку это не мой домен.

Ответ 9

Поскольку виртуальный метод использует определенный тип экземпляра-объекта для определения выполняемой реализации (в отличие от объявленного типа ссылочной переменной)

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

Поэтому они несовместимы.

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

Но, поскольку у вас уже есть эти статические методы, и теперь их необходимо переопределить, вы можете решить свою проблему следующим образом: Добавьте методы виртуального экземпляра в базовый класс, которые просто делегируют статическим методам, а затем переопределяют эти методы оболочки виртуального экземпляра (а не статические) в каждом производном подклассе, если это необходимо...

Ответ 10

На самом деле можно комбинировать виртуальные и статические для метода или члена с помощью ключевого слова new вместо virtual.

Вот пример:

class Car
{
    public static int TyreCount = 4;
    public virtual int GetTyreCount() { return TyreCount; }
}
class Tricar : Car
{
    public static new int TyreCount = 3;
    public override int GetTyreCount() { return TyreCount; }
}

...

Car[] cc = new Car[] { new Tricar(), new Car() };
int t0 = cc[0].GetTyreCount(); // t0 == 3
int t1 = cc[1].GetTyreCount(); // t1 == 4

Очевидно, значение TyreCount могло быть установлено в переопределенном методе GetTyreCount, но это позволяет избежать дублирования значения. Можно получить значение как из класса, так и из экземпляра класса.

Теперь кто-то может найти действительно интеллектуальное использование этой функции?

Ответ 11

Mart получил это право с ключевым словом "новое". Я на самом деле приехал сюда, потому что мне нужен этот тип функциональности, и решение Mart прекрасно работает. На самом деле я сделал это лучше и сделал абстрактное абстрактное метод базового класса, чтобы заставить программиста предоставить это поле.

Мой сценарий был следующим:

У меня есть базовый класс HouseDeed. Каждый тип дома получен из HouseDeed должен иметь цену.

Вот неполный базовый класс HouseDeed:

public abstract class HouseDeed : Item
{
    public static int m_price = 0;
    public abstract int Price { get; }
    /* more impl here */
}

Теперь рассмотрим два типа производных типов:

public class FieldStoneHouseDeed : HouseDeed
{
    public static new int m_price = 43800;
    public override int Price { get { return m_price; } }
    /* more impl here */
}

и...

public class SmallTowerDeed : HouseDeed
{
    public static new int m_price = 88500;
    public override int Price { get { return m_price; } }
    /* more impl here */
}

Как вы можете видеть, я могу получить доступ к цене дома с помощью типа SmallTowerDeed.m_price и экземпляра нового SmallTowerDeed(). Цена И, будучи абстрактным, этот механизм заставляет программиста поставлять цену за каждый новый тип производного дома.

Кто-то указал, что "статические виртуальные" и "виртуальные" концептуально противоречат друг другу. Я не согласен. В этом примере статические методы не нуждаются в доступе к данным экземпляра, и поэтому требования, которые (1) могут быть доступны только через TYPE, и что (2) цена будет предоставлена, выполняются.

Ответ 12

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

Объявление переопределения не может изменить доступность виртуального метода. Как метод переопределения, так и виртуальный метод должны иметь один и тот же модификатор уровня доступа.

Вы не можете использовать новые, статические или виртуальные модификаторы для изменения метода переопределения.

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

Ответ 13

Существует способ принудительного наследования "абстрактных статических" методов из абстрактного общего класса. Смотрите следующее:

public abstract class Mother<T> where T : Mother<T>, new()
{
    public abstract void DoSomething();

    public static void Do()
    {
        (new T()).DoSomething();
    }

}

public class ChildA : Mother<ChildA>
{
    public override void DoSomething() { /* Your Code */ }
}

public class ChildB : Mother<ChildB>
{
    public override void DoSomething() { /* Your Code */ }
}

Пример (с использованием предыдущей Матери):

public class ChildA : Mother<ChildA>
{
    public override void DoSomething() { Console.WriteLine("42"); }
}

public class ChildB : Mother<ChildB>
{
    public override void DoSomething() { Console.WriteLine("12"); }
}

public class Program
{
    static void Main()
    {
        ChildA.Do();  //42
        ChildB.Do();  //12
        Console.ReadKey();
    }
}

Это не так здорово, поскольку вы можете наследовать только один абстрактный класс, и он попросит вас проявить снисходительность к вашей новой() реализации.

Больше, я думаю, это будет дорогостоящим по памяти в зависимости от размера ваших унаследованных классов. Если у вас проблема с памятью, вам нужно будет установить все свойства/переменные после вашего нового в общедоступном методе, что является ужасным способом иметь значения по умолчанию.

Ответ 14

Вы можете использовать новое ключевое слово

namespace AspDotNetStorefront
{
    // This Class is need to override StudioOnlineCommonHelper Methods in a branch
    public class StudioOnlineCommonHelper : StudioOnlineCore.StudioOnlineCommonHelper
    {
        //
        public static new void DoBusinessRulesChecks(Page page)
        {
            StudioOnlineCore.StudioOnlineCommonHelper.DoBusinessRulesChecks(page);
        }
    }
}