Скрыть метод базового класса от производного класса, но все еще видимый вне сборки - PullRequest
0 голосов
/ 10 июля 2009

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

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

Плагины описываются с помощью интерфейса, который используется основной программой (чтобы получить подпись для вызова DispatchTaskToPlugin) и самими плагинами как контракт API:

namespace AppServer.Plugin.Common
{
     public interface IAppServerPlugin
     {
        void Register();
        void DispatchTaskToPlugin(Task t);
        // Other methods omitted
     }
}

В основной части программы вызывается Register(), чтобы плагин мог зарегистрировать свои методы обратного вызова в базовом классе, а затем вызывается DispatchTaskToPlugin() для запуска плагина.

Сами плагины состоят из двух частей. Существует базовый класс, который реализует структуру для плагина (настройка, ведение домашнего хозяйства, разборка и т. Д.) Это где DispatchTaskToPlugin фактически определено:

namespace AppServer.Plugin
{
    abstract public class BasePlugin : MarshalByRefObject,
           AppServer.Plugin.Common.IAppServerPlugin
    {

        public void DispatchTaskToPlugin(Task t)
        {
            // ...
            // Eventual call to actual plugin code
            //
        }

        // Other methods omitted
    }
}

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

namespace AppServer.Plugin
{
    public class Plugin : BasePlugin
    {
        override public void Register()
        {
             // Calls a method in the base class to register itself.
        }
        // Various callback methods, business logic, etc...
    }
}

Теперь в базовом классе (BasePlugin) я реализовал все виды вспомогательных методов, сбор данных и т. Д. Для использования плагинов. Все кошерно, за исключением этого затяжного метода DispatchTaskToPlugin().

Это , а не , который должен вызываться из реализаций класса Plugin - они его не используют. Это нужно только диспетчеру в основной части программы. Как можно запретить производным классам (Plugin) видеть метод в базовом классе (BasePlugin/DispatchTaskToPlugin), но при этом иметь его видимым снаружи сборки?

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

Предложения

Ответы [ 2 ]

1 голос
/ 10 июля 2009

Вы можете реализовать DispatchTaskToPlugin в частном порядке в BasePlugin, используя явную реализацию

public class Task
{
}

 public interface IAppServerPlugin     
 {        
     void Register();        
     void DispatchTaskToPlugin(Task t);        
 }

abstract public class BasePlugin : MarshalByRefObject, IAppServerPlugin    
{
    public abstract void Register();

    void IAppServerPlugin.DispatchTaskToPlugin(Task t)
    {
    } 
}

public class Plugin : BasePlugin    
{       
    override public void Register()        
    {             
    }   

    public void Something()
    {
        this.DispatchTaskToPlugin(null); // Doesn't compile
        base.DispatchTaskToPlugin(null); // Doesn't compile
    }

}

class Program
{
    static void Main(string[] args)
    {
        Plugin x;
        x.DispatchTaskToPlugin(null); // Doesn't compile
    }
}
1 голос
/ 10 июля 2009

Если плагины действительно предназначены только для переопределения одного метода, я предлагаю вам сделать так, чтобы они реализовали интерфейс только с одним методом. Тогда ваш текущий BasePlugin может использовать композицию вместо наследования, чтобы иметь дело с "настоящим" плагином просто на интерфейсе. Может потребоваться передать что-то в Register, чтобы плагин мог подписаться на события, но это также может быть выражено как интерфейс, чтобы плагин видел только то, что вы хотите.

...