Прочитать аргумент события после ожидания
У меня есть аппаратный компонент, который я использую для связи по протоколу TCP. Класс, управляющий им, имеет 3 задания: запуск устройства, прослушивание входящих сообщений и поднятие event
когда сообщение получено:
public class Hardware
{
public event Action<string> OnHardwareMessage;
private NetworkStream stream = new NetworkStream();
public Hardware()
{
Task.Factory.StartNew(() => { Listen(); });
}
private void Listen()
{
//listen to TCP port and raise an event when a message is received
byte[] bytes = new byte[1024];
int bytesRead = stream.Read(bytes, 0, bytes.Length);
string response = Encoding.ASCII.GetString(bytes, 0, bytesRead);
if (OnHardwareMessage != null)
OnHardwareMessage(response);
}
public void Trigger()
{
//Trigger the hardware component
//the response usually takes up to 5 seconds to arrive
}
}
Этот класс используется в цикле внутри view-model
:
public class MainViewModel
{
private static EventWaitHandle hardwareWaiter =
new EventWaitHandle(false, EventResetMode.AutoReset);
private Hardware hardware = new Hardware();
//what i'm doing now is holding a field for incoming event results
private string hardwareResult;
public MainViewModel()
{
hardware.OnHardwareMessage += hardware_OnHardwareMessage;
while (true)
{
hardware.Trigger();
if (hardwareWaiter.WaitOne(10000))
{
//is it possible to read the event argument here?
//do something with the event argument
someObservableCollection.Add(hardwareResult);
//clear the value
hardwareResult = string.Empty;
}
else
{
throw new Exception("Hardware did not respond on time");
}
}
}
//event listener for hardware events
private void hardware_OnHardwareMessage(string message)
{
hardwareResult = message;
hardwareWaiter.Set();
}
}
Я запускаю устройство и жду ответа до 10 секунд. То, что я сейчас делаю, - это удержание поля области действия класса, назначение сообщения, полученного внутри прослушивателя событий, чтение его внутри цикла и очистка его.
У меня вопрос, есть ли какой-нибудь встроенный механизм, который мог бы позволить мне прочитать аргумент события сразу после EventWaitHandle
было сообщено (за пределами слушателя события).
1 ответ
Я бы не стал основывать это на событиях. Может быть, ваш слушатель должен выставить BlockingCollection
это представляет входящий поток сообщений. Затем читатели могут извлечь из этой коллекции тайм-аут. Если время ожидания истекло, сообщение не принимается и не теряется (это условие гонки, которое у вас есть сейчас).
Если вы настаиваете на использовании событий, используйте замыкание для передачи состояния сообщения:
string hardwareResult = null;
Action handler = (...) =>
{
hardwareResult = message;
hardwareWaiter.Set();
};
hardware.OnHardwareMessage += handler;
Таким образом, вам нужна только локальная переменная, которая имеет более узкую область, чем поле.
Также есть обычная ошибка TCP: вы предполагаете прочитать сообщение целиком. Вместо этого вы можете читать по одному байту за раз.