我已经实现了一个SqlListener类,它使用SqlDependency来等待SQL数据库中的更改。在我的业务工作流程中的某一点,我需要等待数据库中出现的记录。找到请求的记录时,SqlListener会触发事件。这很好用。我可以通过输入While循环使其工作,并等到我检测到返回的事件。但这不是理想的设计。它使处理器旋转很多徒劳。
我想以更聪明的方式等待活动。我阅读了很多关于使用Task,NotificationDelegate,ManualResetEvent等的建议....但我无法将它们全部整合在一起。
简化示例可能会使其更容易理解。这是我当前的设置有效。但如果可能的话,我想摆脱丑陋的while循环。
private const int MaxWaitTime = 5;
private SqlListener<RecordType> _recordListener;
private RecordType _record;
/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
// Initiate listening for record
_recordListener = new SqlListener<RecordType>();
_recordListener.SqlModified += SqlListener_SqlModified;
_recordListener.StartListening(requestedId);
// Wait until record is found
var startTime = DateTime.Now;
while (_record == null &&
DateTime.Now.Subtract(startTime).TotalSeconds < MaxWaitTime)
{
Thread.Sleep(1);
}
// Stop listening
_recordListener.SqlModified -= SqlListener_SqlModified;
_recordListener.Dispose();
_recordListener = null;
// Return record
return _record;
}
private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
_record = (RecordType)args.Record;
}
答案 0 :(得分:0)
您可以选择Timer和事件,而不是使用While。类似的东西:
public class ListenerWaiting
{
public ListenerWaiting(int waitingTimeSeconds)
{
_waitSeconds = waitingTimeSeconds;
}
private int _waitSeconds;
private System.Timers.Timer _timer;
private Listener _listener;
public event EventHandler<string> ListenerDone;
public void Listen(int listeningPeriodSeconds)
{
_listener = new Listener(listeningPeriodSeconds * 1000);
_listener.ListenerCompleted += ListenerListenerCompleted;
_timer = new System.Timers.Timer(_waitSeconds * 1000) {Enabled = true};
_timer.Elapsed += TimerElapsed;
}
void ListenerListenerCompleted(object sender, string e)
{
StopTimer();
StopListener();
if (ListenerDone != null)
ListenerDone(this, "Waiting success! Message was: " + e);
}
void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
StopTimer();
StopListener();
if (ListenerDone != null)
ListenerDone(this, "Waited longer than set, aborted waiting...");
}
private void StopTimer()
{
_timer.Stop();
_timer.Elapsed -= TimerElapsed;
_timer = null;
}
private void StopListener()
{
_listener.ListenerCompleted -= ListenerListenerCompleted;
_listener = null;
}
}
public class Listener
{
private System.Timers.Timer _timer;
private string _listeningPeriodSeconds;
public event EventHandler<string> ListenerCompleted;
public Listener(int listeningPeriodSeconds)
{
_listeningPeriodSeconds = listeningPeriodSeconds.ToString();
_timer = new System.Timers.Timer(listeningPeriodSeconds) { Enabled = true };
_timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Elapsed -= TimerElapsed;
_timer = null;
if (ListenerCompleted != null)
ListenerCompleted(this, _listeningPeriodSeconds);
}
}
...然后用:
消费它 static void Main(string[] args)
{
var wait = new ListenerWaiting(5);
wait.ListenerDone += WaitListenerDone;
wait.Listen(3);
Console.ReadLine();
}
static void WaitListenerDone(object sender, string e)
{
Console.WriteLine(e);
}
我想我可以为课程找到更好的名字,但你会明白这一点;)
答案 1 :(得分:0)
事实上,解决方案比我最初想的更简单。当我改述我的问题并再次搜索时,我找到了它。在我的问题中已经提到的ManualResetEvent被证明是最简单的解决方法。
我所要做的就是添加一个ManualResetEvent并将其设置为wait; - )
private const int MaxWaitTime = 5000;
private SqlListener<RecordType> _recordListener;
private RecordType _record;
private readonly ManualResetEvent _recordWaiter = new ManualResetEvent(false);
/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
// Initiate listening for record
_recordListener = new SqlListener<RecordType>();
_recordListener.SqlModified += SqlListener_SqlModified;
_recordListener.StartListening(requestedId);
// Wait synchronously until record is found
_recordWaiter.WaitOne(MaxWaitTime);
// Stop listening
_recordListener.SqlModified -= SqlListener_SqlModified;
_recordListener.Dispose();
_recordListener = null;
// Return record
return _record;
}
private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
_record = (RecordType)args.Record;
_recordWaiter.Set();
}