Обработка событий C# (по сравнению с Java)

Я сам исследую ту же проблему. Документация PyPa рекомендует макет, описанный в «родном» подкаталоге: https://github.com/pypa/sample-namespace-packages

Я нахожу структуру единого пакета, описанную ниже, очень полезно, см. обсуждение тестирования «установленной» версии. https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure Я думаю, что это можно распространить на несколько пакетов. Будет публиковать, как я узнаю больше.

11
задан Richard Walton 8 October 2008 в 05:06
поделиться

9 ответов

Вы создали бы четыре события и методы для повышения их, наряду с новым находящимся в EventArgs классом для указания на ошибку:

public class ExceptionEventArgs : EventArgs
{
    private readonly Exception error;

    public ExceptionEventArgs(Exception error)
    {
         this.error = error;
    }

    public Error
    {
         get { return error; }
    }
}

public class Computer
{
    public event EventHandler Started = delegate{};
    public event EventHandler Stopped = delegate{};
    public event EventHandler Reset = delegate{};
    public event EventHandler<ExceptionEventArgs> Error = delegate{};

    protected void OnStarted()
    {
        Started(this, EventArgs.Empty);
    }

    protected void OnStopped()
    {
        Stopped(this, EventArgs.Empty);
    }

    protected void OnReset()
    {
        Reset(this, EventArgs.Empty);
    }

    protected void OnError(Exception e)
    {
        Error(this, new ExceptionEventArgs(e));
    }
}

Классы затем подписались бы на событие с помощью или метода или анонимная функция:

someComputer.Started += StartEventHandler; // A method
someComputer.Stopped += delegate(object o, EventArgs e)
{ 
    Console.WriteLine("{0} has started", o);
};
someComputer.Reset += (o, e) => Console.WriteLine("{0} has been reset");

Несколько вещей отметить о вышеупомянутом:

  • Методы OnXXX защищены так, чтобы производные классы могли сгенерировать события. Это не всегда необходимо - делают это, как Вы считаете целесообразным.
  • delegate{} часть на каждом объявлении события является просто приемом, чтобы избежать необходимости делать пустую проверку. Это не подписывает никакой-op обработчик событий на каждое событие
  • Объявления события являются подобными полю событиями. То, что на самом деле создается, является и переменной и событием. В классе Вы видите переменную; вне класса Вы видите событие.

См. мою статью событий/делегатов для намного большего количества детали о событиях.

16
ответ дан 3 December 2019 в 03:05
поделиться

Необходимо будет определить единственного делегата к этому

public delegate void ComputerEvent(object sender, ComputerEventArgs e);

ComputerEventArgs был бы определен как это:

public class ComputerEventArgs : EventArgs
{
    // TODO wrap in properties
    public Computer computer;
    public Exception error;

    public ComputerEventArgs(Computer aComputer, Exception anError)
    {
        computer = aComputer;
        error = anError;
    }

    public ComputerEventArgs(Computer aComputer) : this(aComputer, null)
    {
    }
}

Класс, который запускает события, имел бы их:

public YourClass
{
    ...
    public event ComputerEvent ComputerStarted;
    public event ComputerEvent ComputerStopped;
    public event ComputerEvent ComputerReset;
    public event ComputerEvent ComputerError;
    ...
}

Это - то, как Вы присваиваете обработчики событиям:

YourClass obj = new YourClass();
obj.ComputerStarted += new ComputerEvent(your_computer_started_handler);

Ваш обработчик:

private void ComputerStartedEventHandler(object sender, ComputerEventArgs e)
{
   // do your thing.
}
5
ответ дан 3 December 2019 в 03:05
поделиться

Основное различие - то, что в C# события не основаны на интерфейсе. Вместо этого издатель события объявляет делегата, о котором можно думать как указатель функции (хотя не точно то же :-)). Подписчик затем реализует прототип события как обычный метод и добавляет новый экземпляр делегата в цепочке обработчика событий издателя. Читайте больше о делегатах и событиях.

Можно также считать короткое сравнение C# по сравнению с событиями Java здесь.

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

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

  1. Создайте класс, который будет содержать параметры события (полученный из EventArgs).
public class ComputerEventArgs : EventArgs 
{
  Computer computer; 
  // constructor, properties, etc.
}
  1. Создайте общественное мероприятие на классе, который должен запустить событие.
    class ComputerEventGenerator  // I picked a terrible name BTW.
    {
      public event EventHandler<ComputerEventArgs> ComputerStarted;
      public event EventHandler<ComputerEventArgs> ComputerStopped;
      public event EventHandler<ComputerEventArgs> ComputerReset;
    ...
    }
  1. Назовите события.
    class ComputerEventGenerator
    {
    ...
      private void OnComputerStarted(Computer computer) 
      {
        EventHandler<ComputerEventArgs> temp = ComputerStarted;
        if (temp != null) temp(this, new ComputerEventArgs(computer)); // replace "this" with null if the event is static
      }
     }
  1. Присоедините обработчик для события.
    void OnLoad()
    {
      ComputerEventGenerator computerEventGenerator = new ComputerEventGenerator();
      computerEventGenerator.ComputerStarted += new  EventHandler<ComputerEventArgs>(ComputerEventGenerator_ComputerStarted);
    }
  1. Создайте обработчик, который Вы просто присоединили (главным образом путем нажатия клавиши Tab в VS).
    private void ComputerEventGenerator_ComputerStarted(object sender, ComputerEventArgs args)
    {
      if (args.Computer.Name == "HAL9000")
         ShutItDownNow(args.Computer);
    }
  1. Не забывайте отсоединять обработчик, когда Вы будете сделаны. (Упущение сделать это - самый большой источник утечек памяти в C#!)
    void OnClose()
    {
      ComputerEventGenerator.ComputerStarted -= ComputerEventGenerator_ComputerStarted;
    }

И вот именно!

Править: Я честно не могу выяснить, почему мои пронумерованные точки все появляются как "1". Я ненавижу компьютеры.

2
ответ дан 3 December 2019 в 03:05
поделиться

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

public delegate void ComputerStartedDelegate(Computer computer);
protected event ComputerStartedDelegate ComputerStarted;
public void OnComputerStarted(Computer computer)
{
    if (ComputerStarted != null)
    {
        ComputerStarted.Invoke(computer);
    }
}
protected void someMethod()
{
    //...
    computer.Started = true;  //or whatever
    OnComputerStarted(computer);
    //...
}

любой объект может 'послушать' для этого события просто:

Computer comp = new Computer();
comp.ComputerStarted += new ComputerStartedDelegate(
    this.ComputerStartedHandler);

protected void ComputerStartedHandler(Computer computer)
{
    //do something
}

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

  • делегат определяет подпись/интерфейс для обработчика событий / слушатель
  • участник данных о событии является списком 'слушателей'

слушатели удалены с помощью - = синтаксис вместо + =

1
ответ дан 3 December 2019 в 03:05
поделиться

В c# событиях делегаты. Они ведут себя похожим способом к указателю функции в C/C++, но являются фактическими классами, полученными из Системы. Делегат.

В этом случае создайте пользовательский класс EventArgs для передачи Компьютерного объекта.

public class ComputerEventArgs : EventArgs
{
  private Computer _computer;

  public ComputerEventArgs(Computer computer) {
    _computer = computer;
  }

  public Computer Computer { get { return _computer; } }
}

Затем выставьте события от производителя:

public class ComputerEventProducer
{
  public event EventHandler<ComputerEventArgs> Started;
  public event EventHandler<ComputerEventArgs> Stopped;
  public event EventHandler<ComputerEventArgs> Reset;
  public event EventHandler<ComputerEventArgs> Error;

  /*
  // Invokes the Started event */
  private void OnStarted(Computer computer) {
    if( Started != null ) {
      Started(this, new ComputerEventArgs(computer));
    }
  }

  // Add OnStopped, OnReset and OnError

}

Потребитель событий затем связывает функцию-обработчик с каждым событием на потребителе.

public class ComputerEventConsumer
{
  public void ComputerEventConsumer(ComputerEventProducer producer) {
    producer.Started += new EventHandler<ComputerEventArgs>(ComputerStarted);
    // Add other event handlers
  }

  private void ComputerStarted(object sender, ComputerEventArgs e) {
  }
}

Когда ComputerEventProducer называет OnStarted, событие Started вызывается, который в свою очередь назовет ComputerEventConsumer. Метод ComputerStarted.

1
ответ дан 3 December 2019 в 03:05
поделиться

Делегат объявляет функциональную подпись, и когда она используется в качестве события на классе, она также действует как набор включенных в список целей вызова. + = и - = синтаксис на событии привык добавлять цель к списку.

Учитывая следующих делегатов, используемых в качестве событий:

// arguments for events
public class ComputerEventArgs : EventArgs
{
    public Computer Computer { get; set; }
}

public class ComputerErrorEventArgs : ComputerEventArgs
{
    public Exception Error  { get; set; }
}

// delegates for events
public delegate void ComputerEventHandler(object sender, ComputerEventArgs e);

public delegate void ComputerErrorEventHandler(object sender, ComputerErrorEventArgs e);

// component that raises events
public class Thing
{
    public event ComputerEventHandler Started;
    public event ComputerEventHandler Stopped;
    public event ComputerEventHandler Reset;
    public event ComputerErrorEventHandler Error;
}

Вы подписались бы на те события со следующим:

class Program
{
    static void Main(string[] args)
    {
        var thing = new Thing();
        thing.Started += thing_Started;
    }

    static void thing_Started(object sender, ComputerEventArgs e)
    {
        throw new NotImplementedException();
    }
}

Хотя аргументы могли быть чем-либо, объектный отправитель и EventArgs e являются конвенцией, это используется очень последовательно. + = thing_started сначала создаст экземпляр делегата, указывающего на целевой метод, затем добавить его к событию.

На самом компоненте Вы обычно добавляли бы методы для увольнения событий:

public class Thing
{
    public event ComputerEventHandler Started;

    public void OnStarted(Computer computer)
    {
        if (Started != null)
            Started(this, new ComputerEventArgs {Computer = computer});
    }
}

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

Другое улучшение должно было бы использовать универсального делегата EventHandler вместо того, чтобы объявить конкретного делегата к каждому типу args.

public class Thing
{
    public event EventHandler<ComputerEventArgs> Started;
    public event EventHandler<ComputerEventArgs> Stopped;
    public event EventHandler<ComputerEventArgs> Reset;
    public event EventHandler<ComputerErrorEventArgs> Error;
}
0
ответ дан 3 December 2019 в 03:05
поделиться

Всем огромное спасибо за Ваши ответы! Наконец я начинаю понимать то, что продолжается. Всего одна вещь; кажется, что, если бы каждое событие имело различное число/тип аргументов, я должен был бы создать другое:: класс EventArgs для контакта с ним:

public void computerStarted(Computer computer);
public void computerStopped(Computer computer);
public void computerReset(Computer computer);
public void breakPointHit(Computer computer, int breakpoint);
public void computerError(Computer computer, Exception exception);

Это потребовало бы, чтобы три класса имели дело с событиями!? (Хорошо два пользовательских, и одно использование EventArgs по умолчанию. Пустой класс)

Удачи!

0
ответ дан 3 December 2019 в 03:05
поделиться

Хорошо, ЗАКЛЮЧИТЕЛЬНОЕ разъяснение!: Таким образом, это является в значительной степени лучшим, я могу сделать мудрый кодом для реализации тех событий?

   public class Computer {

        public event EventHandler Started;

        public event EventHandler Stopped;

        public event EventHandler Reset;

        public event EventHandler<BreakPointEvent> BreakPointHit;

        public event EventHandler<ExceptionEvent> Error;

        public Computer() {
            Started = delegate { };
            Stopped = delegate { };
            Reset = delegate { };
            BreakPointHit = delegate { };
            Error = delegate { };
        }

        protected void OnStarted() {
            Started(this, EventArgs.Empty);
        }

        protected void OnStopped() {
            Stopped(this, EventArgs.Empty);
        }

        protected void OnReset() {
            Reset(this, EventArgs.Empty);
        }

        protected void OnBreakPointHit(int breakPoint) {
            BreakPointHit(this, new BreakPointEvent(breakPoint));
        }

        protected void OnError(System.Exception exception) {
            Error(this, new ExceptionEvent(exception));
        }
    }
}
0
ответ дан 3 December 2019 в 03:05
поделиться
Другие вопросы по тегам:

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