Дизайн класса C # - что я могу использовать вместо «статического резюме»? - PullRequest
9 голосов
/ 24 мая 2010

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

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 ]

5 голосов
/ 24 мая 2010

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

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

4 голосов
/ 24 мая 2010

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

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

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

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

3 голосов
/ 25 мая 2010

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

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

Рассмотрим свойство 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;

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

2 голосов
/ 24 мая 2010

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

public interface IMagic
{
    int MagicId { get; }
}

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

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

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

0 голосов
/ 25 мая 2010

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

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

0 голосов
/ 25 мая 2010

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

0 голосов
/ 25 мая 2010

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

0 голосов
/ 24 мая 2010

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

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

0 голосов
/ 24 мая 2010

Не большой поклонник этой опции, но ...

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

Вы перемещаете ошибку из времени компиляции во время выполнения, хотя это довольно уродливо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...