Дизайн класса C# - что я могу использовать вместо “статического краткого обзора”?

Я хочу сделать следующее

public abstract class MyAbstractClass
{
    public static abstract int MagicId
    {
        get;
    }

    public static void DoSomeMagic()
    {
        // Need to get the MagicId value defined in the concrete implementation
    }
}

public class MyConcreteClass : MyAbstractClass
{
    public static override int MagicId
    {
        get { return 123; }
    }
}

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

Я понимаю, почему я не могу сделать этого - какие-либо рекомендации для дизайна, который достигнет почти такого же результата?

(Для ясности - я пытаюсь предоставить библиотеке абстрактный базовый класс, но конкретные версии ДОЛЖНЫ реализовать самих несколько свойств/методов и да, существуют серьезные основания для хранения ее статичны.)

9
задан Community 23 May 2017 в 10:33
поделиться

9 ответов

Возможно, сработает шаблон Singleton? Ссылка на статью MSDN, описывающую, как реализовать синглтон в C #:

http://msdn.microsoft.com/en-us/library/ff650316.aspx

В вашем конкретном примере экземпляр Singelton может расширять абстрактный базовый класс с вашим MagicId в нем.

Просто мысль :)

4
ответ дан 4 December 2019 в 14:26
поделиться

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

Это, или используйте отражение. Но вы не можете гарантировать во время компиляции, что производный класс статически реализует определенное свойство.

0
ответ дан 4 December 2019 в 14:26
поделиться

Вы принципиально не можете заставить DoSomeMagic () работать с текущим дизайном. Вызов MyConcreteClass.DoSomeMagic в исходном коде будет переведен в MyAbstractClasss.DoSomeMagic в IL. Тот факт, что он был первоначально вызван с использованием MyConcreteClass , утрачен.

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

5
ответ дан 4 December 2019 в 14:26
поделиться

Почему бы просто не сделать его нестатическим членом?

0
ответ дан 4 December 2019 в 14:26
поделиться

Я сомневаюсь, что есть «веские причины» для статичности абстрактных членов.

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

Рассмотрим свойство IList.IsFixedSize . Это действительно свойство типа IList , а не какой-либо конкретный экземпляр (т.е. любой T [] будет иметь фиксированный размер; он не будет варьируются от одного T [] к другому). Но все же он должен быть членом экземпляра.Почему? Поскольку , поскольку несколько типов могут реализовывать IList , он будет изменяться от одного IList к другому.

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

int magicId;
if (concreteObject is MyConcreteClass) {
    magicId = MyConcreteClass.MagicId;
} else if (concreteObject is MyOtherConcreteClass) {
    magicId = MyOtherConcreteClass.MagicId;
}

Почему такой беспорядок? Это намного лучше, не так ли?

int magicId = concreteObject.MagicId;

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

3
ответ дан 4 December 2019 в 14:26
поделиться

Звучит как моностат, возможно? http://c2.com/cgi/wiki?MonostatePattern

0
ответ дан 4 December 2019 в 14:26
поделиться

Шаблон провайдера, используемый, например, провайдером членства ASP.NET, может быть тем, что вы ищете.

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

0
ответ дан 4 December 2019 в 14:26
поделиться

Ваш лучший вариант - использовать интерфейс с MagicId только с помощью сеттера

public interface IMagic
{
    int MagicId { get; }
}

По природе Static означает, что может быть только один (да, как Highlander), вы не можете переопределить их.

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

Хорошая причина для сохранения статических переменных также означает, что вам НЕ нужно переопределять их в дочернем классе.

2
ответ дан 4 December 2019 в 14:26
поделиться

Я не большой поклонник этого варианта, но...

Вы можете объявить свойство статическим, не абстрактным, виртуальным и бросить NotImplementedException, который возвращает сообщение об ошибке, что метод должен быть переопределен в производном классе.

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

0
ответ дан 4 December 2019 в 14:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: