Как передать абстрактный метод в качестве ссылки? - PullRequest
0 голосов
/ 06 мая 2018

Признаюсь, я делаю домашнее задание и застрял в этом одном вопросе (часть A). Как передать метод уведомления в качестве ссылки на железнодорожный сигнал? Разве я не могу просто узнать, какой класс был вызван в абстрактном конструкторе, а затем напечатать имя класса в методе notify? Например:

RailwayUser

private string className;

public RailwayUser()
{ 
    Type type = this.GetType();
    className = type.Name;
}

public void PrintClassName()
{
  Console.Writeline(className);
}

RailwaySignal Класс

public void Notify()
{
    foreach(RailwayUser u in _watches)
    {
        u.PrintClassName();
        u.Notice(State)
    }
}

enter image description here

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Этот тип кода / дизайна имеет недостатки, поскольку он RailwayUser регистрирует ссылку на объект со списком _watchers в классе RailWaySignal, который, в свою очередь, вызывает открытый метод Notice для каждого пользователь, когда вызывается Notify, а не Event Signaling или Function Pointer. На самом деле public _watchers опасен, так как может быть очищен любым пользователем, хотя это может быть модерировано с помощью доступа к свойству

Код с выпуском

public void Notify()
{
    foreach(RailwayUser u in _watches)
    {
        u.PrintClassName();
        u.Notice(State)
    }
}

Ниже приведен фактический код с использованием событий и делегатов:

Правильная версия

Фрагмент кода онлайн - https://www.jdoodle.com/embed/v0/uEc

void Main()
{
    List<RailwayUser> railwayUsers = new List<RailwayUser>();

    railwayUsers.Add(new RailwayUser());
    railwayUsers.Add(new RailwayUser());

    RailwayUser.TestNotification();
}

public enum Colour
{
    Red,
    Green,
    NoSignal
}

public class RailwaySignal
{
    public string Name {get; set;}

    public RailwaySignal(string railwaySignalName)
    {
        Name = railwaySignalName;
    }   

    // Delegate for handling event
    public delegate void RailwaySignalEventHandler(object source, Colour e);

    // Delagate object for handling event
    private RailwaySignalEventHandler _railwaySignalEvent;

    // Event Accessor
    public event RailwaySignalEventHandler RailwaySignalEvent
    {
        add
        {
            lock (this)
            {
                _railwaySignalEvent += value;
            }
        }

        remove
        {
            lock (this)
            {
                _railwaySignalEvent -= value;
            }
        }
    }

    // Invoke Event for subscribed clients
    private void Notify()
    {
        if (_railwaySignalEvent != null)
            _railwaySignalEvent.Invoke(this, Colour.Green);
    }

    // Test the Event Invocation
    public void TestEvent()
    {
        Notify();
    }
}

public class RailwayUser
{
    private static RailwaySignal railwaySignal { get; set;} = new RailwaySignal("Signal1");

    public RailwayUser()
    {
        railwaySignal.RailwaySignalEvent += this.Notice;        
    }

    public static void TestNotification()
    {
        railwaySignal.TestEvent();
    }

    public void Notice(object sender, Colour color)
    {       
        Console.WriteLine($"Notice Called, Colour is :: {color}, Sender is :: {((RailwaySignal)sender).Name}");
    }
}

Результат

Notice Called, Colour is :: Green, Sender is :: Signal1
Notice Called, Colour is :: Green, Sender is :: Signal1

Важные сведения

  • Подпись события: (object source, Colour e), которая помогает передавать соответствующую информацию в вызываемый RailwayUser. Теперь мы знаем, что RailwaySignal вызывает уведомление RailwayUser и его значение Color
  • Событие / Делегат имеет ту же сигнатуру, что и вызываемый метод (что является основой работы делегата / указателей на функции)
  • Для упрощения RailwayUser - неабстрактный класс
  • Событие выполняется с использованием метода Notify() внутри RailwaySignal, мы вызываем его искусственно, используя TestNotification() внутри RailwayUser только для демонстрации, но в идеале оно должно быть внутренне запущено и должно передаваться в текущем состоянии, как Color
  • Предопределенные делегаты, такие как Func, Action, довольно часто используются для аналогичного механизма уведомления. Они внутренне работают с использованием аналогичного механизма, хотя объявление явного event, который внутренне является delegate, является хорошо определенным шаблоном специально для элементов управления UI
  • Стандартные события, предоставляемые платформой .Net, имеют подпись object sender, EventArgs e, где EventArgs может переносить всю информацию от исполнителя Event (RailwaySignal) к получателю события (RailwayUser)
0 голосов
/ 06 мая 2018

Это похоже на шаблон Observer. Вы можете передать SubClass, который наследуется от RailwayUser экземпляра объекта в RailwaySignal class

Ваш RailwayUser класс должен создать public abstract void Notice(Colour state) метод.

public abstract class RailwayUser
{
    private string className;

    public RailwayUser()
    {
        Type type = this.GetType();
        className = type.Name;
    }

    public void PrintClassName()
    {
        Console.WriteLine(className);
    }

    public abstract void Notice(Colour state);
}

Driver класс может наследовать RailwayUser класс, затем переопределить Метод уведомления.

public class Driver : RailwayUser
{
    public override void Notice(Colour state)
    {
        Console.WriteLine($"Driver see the {state.ToString()}");
    }
}

Есть

  1. List<RailwayUser> _watches содержит наблюдаемый объект
  2. использовать SubScript(RailwayUser user) пользователя подписки на _watches List.
  3. RailwayUser Notify(), чтобы вызвать все ваши наблюдаемые метод уведомления.

выглядит так.

public class RailwaySignal
{

    private List<RailwayUser> _watches;

    public Colour Stata { get; set; }

    public RailwaySignal()
    {
        _watches = new List<RailwayUser>();
    }

    public void SubScript(RailwayUser user)
    {
        _watches.Add(user);
    }

    public void Notify()
    {
        foreach (RailwayUser u in _watches)
        {
            u.PrintClassName();
            u.Notice(Stata);
        }
    }
}

образец: https://dotnetfiddle.net/GcdGMy


Вы также можете использовать event, чтобы передать метод в RailwaySignal, а затем вызвать Notify метод.

public enum Colour
{
    Green,
    Red,
    Disable
}
public abstract class RailwayUser
{
    private string className;

    public RailwayUser()
    {
        Type type = this.GetType();
        className = type.Name;
    }

    public void PrintClassName()
    {
        Console.WriteLine(className);
    }

    public abstract void Notice(Colour state);
}

public class Driver : RailwayUser
{
    public override void Notice(Colour state)
    {
        Console.WriteLine("Driver see the "+ state.ToString());
    }
}

public class Controller : RailwayUser
{
    public override void Notice(Colour state)
    {
        Console.WriteLine("Controller see the " + state.ToString());
    }
}


public class RailwaySignal
{
    public delegate void NoticeEvent(Colour state);

    public event NoticeEvent Notifys;
    public Colour Stata { get; set; }

    public void Notify()
    {
        if (Notifys != null)
        {
            Notifys(Stata);
        }
    }
}

используйте вот так.

RailwaySignal railway = new RailwaySignal() { Stata = Colour.Green};

railway.Notifys += new Driver().Notice;
railway.Notifys += new Controller().Notice;

railway.Notify();

образец: https://dotnetfiddle.net/GcdGMy

...