C#, реализуйте «статические абстрактные» методы
Вопрос
Недавно я столкнулся с проблемой: кажется, мне нужен «статический абстрактный» метод.Я знаю, почему это невозможно, но как обойти это ограничение?
Например, у меня есть абстрактный класс со строкой описания.Поскольку эта строка является общей для всех экземпляров, она помечена как статическая, но я хочу потребовать, чтобы все классы, производные от этого класса, предоставляли собственное свойство «Описание», поэтому я пометил ее как абстрактную:
abstract class AbstractBase
{
...
public static abstract string Description{get;}
...
}
Конечно, он не скомпилируется.Я думал об использовании интерфейсов, но интерфейсы могут не содержать сигнатур статических методов.
Должен ли я сделать его просто нестатическим и всегда получать экземпляр для получения информации об этом классе?
Есть идеи?
Решение
Комбинировать статическое и абстрактное несколько бессмысленно, да. Идея статики заключается в том, что нет необходимости представлять экземпляр класса для использования рассматриваемого члена; однако с абстрактным можно ожидать, что экземпляр будет производного класса, который обеспечивает конкретную реализацию.
Я могу понять, почему вам нужна такая комбинация, но единственное влияние состоит в том, чтобы отрицать использование реализации this или любых нестатических элементов. То есть родительский класс будет диктовать ограничение в реализации производного класса, даже несмотря на то, что между вызовом абстрактного или «статического абстрактного» члена нет принципиальной разницы (поскольку для обоих потребуется конкретный экземпляр, чтобы выяснить, какую реализацию использовать) р>
Другие советы
Ты не можешь.
Это можно сделать с помощью атрибутов.
Например
[Name("FooClass")]
class Foo
{
}
Если вы не возражаете отложить реализацию, чтобы разумно реализовать свойство Description, вы можете просто сделать
public abstract string ClassDescription {get; }
// ClassDescription is more intention-revealing than Description
И реализующие классы будут делать что-то вроде этого:
static string classDescription="My Description for this class";
override string ClassDescription { get { return classDescription; } }
Затем ваши классы должны следовать договору о наличии описания, но вы предоставляете им разумное решение. Нет способа указать реализацию объектно-ориентированным способом (кроме как через жестокие, хрупкие взломы).
Однако, на мой взгляд, это описание является метаданными класса, поэтому я бы предпочел использовать механизм атрибутов, как уже описывали другие. Если вас особенно беспокоит многократное использование отражения, создайте объект, отражающий атрибут, который вас интересует, и сохраните словарь между типом и описанием. Это сведет к минимуму отражение (кроме проверки типа во время выполнения, что не так уж и плохо). Словарь может храниться как член любого класса, который обычно нуждается в этой информации, или, если это требуется клиентам по всему домену, с помощью одноэлементного или контекстного объекта.
Если он статический, существует только один экземпляр переменной, я не понимаю, как наследование имело бы смысл, если бы мы могли делать то, что вы хотите, используя статические переменные в производных классах. Лично я думаю, что вы идете далеко, чтобы попытаться избежать экземпляра var.
Почему бы не просто классический способ? Р>
abstract class AbstractBase
{
protected string _Description = "I am boring abstract default value";
}
class Foo : AbstractBase {
public Foo() {
_Description = "I am foo!";
}
}
Это не статично, если его нужно вызвать в экземпляре.
Если вы не вызываете его в экземпляре, то в игре нет полиморфизма (т. е. ChildA.Description полностью не относится к ChildB.Description в том, что касается языка).
Возможный обходной путь — определить синглтон вашего производного класса в базовом классе с помощью дженериков.
import System;
public abstract class AbstractBase<T>
where T : AbstractBase<T>, new()
{
private static T _instance = new T();
public abstract string Description { get; }
public static string GetDescription()
{
return _instance.Description;
}
}
public class DerivedClass : AbstractBase<DerivedClass>
{
public override string Description => "This is the derived Class";
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(DerivedClass.GetDescription());
Console.ReadKey();
}
}
Хитрость заключается в том, чтобы сказать своему AbstractBase<T>
некоторые подробности о том, как DerivedClass
реализовано:
- Это новинка с
where T: new()
поэтому он может создать экземпляр Singleton - Оно происходит из самого себя с помощью
where T : AbstractBase<T>
поэтому он знает, что будет реализацияDescription
Сюда _instance
содержит Description
поле, которое можно вызвать в статическом методе GetDescription()
.Это заставляет вас перезаписывать Description
в вашей DerivedClass
и позволяет вам вызывать его значение с помощью DerivedClass.GetDescription()
Вы можете сделать " abstract " базовый метод бросает Exception
, поэтому разработчик " предупрежден " если он пытается вызвать этот метод в дочернем классе без переопределения. Р>
Недостатком является то, что можно расширить класс и не использовать этот метод. Затем обратитесь к другим ответам.