Наследование объектов, переопределения закрытых методов и C # - PullRequest
3 голосов
/ 05 апреля 2011

У меня есть абстрактный класс, определенный другой сборкой (не редактируемый):

public abstract class A
{
    public void Run()
    {
        Go("Hello World");
    }

    protected virtual void Go(string message)
    {
        // Do Nothing
    }
}

Теперь у меня есть библиотека, которую я хочу наследовать от этого класса, которая реализует Go ().Хитрость в том, что я не хочу, чтобы кто-то из моих наследников мог переопределить мою реализацию Go (), но я также не хочу менять подпись каким-либо образом.Я на самом деле хочу, чтобы обе реализации были вызваны.Вот что я получил до сих пор:

public abstract class B_Intercept : A
{
    protected sealed override void Go(string message)
    {
        Console.WriteLine(message);
        Go_Impl(message);
    }

    internal abstract void Go_Impl(string message);
}

public abstract class B : B_Intercept
{
    protected new virtual void Go(string message)
    {
    }

    internal override void Go_Impl(string message)
    {
        Go(message);
    }
}

Теперь мои конечные пользователи могут переключать наследование своего класса с A на B без эффекта (кроме моего Console.WriteLine).

public class C : A // This can be changed to B with no other edits
{
    protected override Go(string message)
    {
        // Do stuff
    }
}

Теперь исходной библиотеке можно дать экземпляр C, он будет помечен как A, а исходная библиотека вызовет Run ().Run будет использовать Go () B_Intercept, который выведет сообщение на консоль, а затем вызовет Go_Impl ().Go_Impl будет запущен в B, который вызовет функцию Go () B, которую можно переопределить с помощью C.

Это кажется очень сложным.

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

Есть ли более простой, более безопасный способ?

1 Ответ

4 голосов
/ 05 апреля 2011

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

Go был предоставлен как virtual метод, и теперь вы пытаетесь скрыть его, в то время как вы хотите сохранить его как можно OO - ( UPDATE ) и не только это, вы также обеспокоены наследуемыми классами, вызывающими базовый метод. Я искренне поздравляю вас с вашими усилиями, заботой и вниманием, но что-то должно дать .

Либо вы должны использовать composition, чтобы обернуть класс A и предоставить только те интерфейсы, которые вы намереваетесь предоставить, и соответствовать вашему дизайну или вы должны использовать inheritance и принять его недостаток, который в основном возникает из-за того, что вы действительно меняете предполагаемое поведение класса. Для моих двух центов я бы выбрал первый вариант: composition. В конце концов, это действительно то, чего вы пытаетесь достичь.

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