문제
은 거기에 좋은 간단한 방법의 함수 호출을 지연시키는 동안 스레드가 계속 실행?
예:
public void foo()
{
// Do stuff!
// Delayed call to bar() after x number of ms
// Do more Stuff
}
public void bar()
{
// Only execute once foo has finished
}
내가 이렇게 하면 사용해서 달성될 수 있는 타이머 및 이벤트 처리기,하지만 내가 궁금 있는 경우에는 표준 c#을 달성하는 방법을 이?
사람이 있는 경우 호기심,그 이유는 필요한 것은 foo()및 바()다른(싱글)클래스에있는 나의 필요를 통해 예외적인 상황에서.문제가 되는 것 이것은 그래서 초기화 foo 요구하는 호텔을 필요로 하는 인스턴스를 푸는 클래스가 생성되...따라서 이 지연된 통화를 바()하는지 확인 foo 은 완전히 instanciated..이 글을 읽고 다시 거의 난다 나쁜 디자인!
편집
나는 포인트에 대한 나쁜 디자인에서 관련 상담!나는 오랫동안 생각할 수 있는 시스템을 개선하기 위해,그러나,이러한 불쾌한 상황 만 이 발생할 경우 예외가 발생하고,모든 다른 시간에는 두 싱글이 공존하는 매니다.나는 생각하지는 않을 겁 messaround 로 불쾌한 비동기-패턴,오히려 내가 형식의 초기화의 하나의 클래스입니다.
해결책
현대 C# 5/6 덕분에 :)
public void foo()
{
Task.Delay(1000).ContinueWith(t=> bar());
}
public void bar()
{
// do stuff
}
다른 팁
나는 이와 같은 것을 찾고 있었다 - 나는 다음을 생각해 냈다. 그러나 그것은 타이머를 사용하지만, 초기 지연에 대해서만 한 번만 사용하고, 아무것도 요구하지 않는다. Sleep
전화 ...
public void foo()
{
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((obj) =>
{
bar();
timer.Dispose();
},
null, 1000, System.Threading.Timeout.Infinite);
}
public void bar()
{
// do stuff
}
(감사합니다 프레드 데시 네스 콜백 내에서 타이머를 처분한다는 아이디어를 위해)
이전 주석가의 디자인 관찰에 동의하는 것 외에도 솔루션 중 어느 것도 나에게 충분히 깨끗하지 않았습니다. .NET 4 제공 Dispatcher
그리고 Task
지연 실행을하는 클래스 현재 스레드에서 매우 간단 :
static class AsyncUtils
{
static public void DelayCall(int msec, Action fn)
{
// Grab the dispatcher from the current executing thread
Dispatcher d = Dispatcher.CurrentDispatcher;
// Tasks execute in a thread pool thread
new Task (() => {
System.Threading.Thread.Sleep (msec); // delay
// use the dispatcher to asynchronously invoke the action
// back on the original thread
d.BeginInvoke (fn);
}).Start ();
}
}
상황에 따라, 나는 이것을 사용하여 분해합니다 ICommand
UI 요소의 왼쪽 마우스 버튼에 묶습니다. 사용자는 두 번 클릭하여 모든 종류의 혼란을 유발합니다. (나는 또한 내가 사용할 수 있다는 것을 안다 Click
/DoubleClick
핸들러이지만 함께 작동하는 솔루션을 원했습니다. ICommand
전반적으로 s).
public void Execute(object parameter)
{
if (!IsDebouncing) {
IsDebouncing = true;
AsyncUtils.DelayCall (DebouncePeriodMsec, () => {
IsDebouncing = false;
});
_execute ();
}
}
그것은 소리와 같은 제어의 창조의 이러한 두 개체 및 그들의 상호 의존 요구를 통제되는 외부적으로,사이가 아니라 클래스 자체.
그것은 실제로 매우 나쁜 디자인입니다. 싱글 톤 자체는 물론 나쁜 디자인입니다.
그러나 실행을 지연시켜야한다면 다음은 다음과 같습니다.
BackgroundWorker barInvoker = new BackgroundWorker();
barInvoker.DoWork += delegate
{
Thread.Sleep(TimeSpan.FromSeconds(1));
bar();
};
barInvoker.RunWorkerAsync();
그러나 이것은 호출 할 것입니다 bar()
별도의 스레드에서. 전화 해야하는 경우 bar()
원래 스레드에서 이동해야 할 수도 있습니다 bar()
호출 RunWorkerCompleted
핸들러 또는 약간의 해킹을합니다 SynchronizationContext
.
글쎄, 나는 "디자인"포인트에 동의해야하지만 ... 다른 사람이 중요한 섹션을 지나간시기를 알리기 위해 모니터를 사용하여 아마도 모니터를 사용할 수있을 것입니다 ...
public void foo() {
// Do stuff!
object syncLock = new object();
lock (syncLock) {
// Delayed call to bar() after x number of ms
ThreadPool.QueueUserWorkItem(delegate {
lock(syncLock) {
bar();
}
});
// Do more Stuff
}
// lock now released, bar can begin
}
public static class DelayedDelegate
{
static Timer runDelegates;
static Dictionary<MethodInvoker, DateTime> delayedDelegates = new Dictionary<MethodInvoker, DateTime>();
static DelayedDelegate()
{
runDelegates = new Timer();
runDelegates.Interval = 250;
runDelegates.Tick += RunDelegates;
runDelegates.Enabled = true;
}
public static void Add(MethodInvoker method, int delay)
{
delayedDelegates.Add(method, DateTime.Now + TimeSpan.FromSeconds(delay));
}
static void RunDelegates(object sender, EventArgs e)
{
List<MethodInvoker> removeDelegates = new List<MethodInvoker>();
foreach (MethodInvoker method in delayedDelegates.Keys)
{
if (DateTime.Now >= delayedDelegates[method])
{
method();
removeDelegates.Add(method);
}
}
foreach (MethodInvoker method in removeDelegates)
{
delayedDelegates.Remove(method);
}
}
}
용법:
DelayedDelegate.Add(MyMethod,5);
void MyMethod()
{
MessageBox.Show("5 Seconds Later!");
}
완벽한 솔루션은 타이머가 지연된 동작을 처리하는 것입니다. FXCOP는 1 초 미만의 간격이있을 때 마음에 들지 않습니다. DataGrid가 열별로 정렬을 완료 한 후에도 내 행동을 지연시켜야합니다. 나는 원샷 타이머 (Autoreset = false)가 해결책이 될 것이라고 생각했으며 완벽하게 작동합니다. 그리고 FXCOP는 경고를 억제 할 수 없습니다!
이것은 이전 버전의 .NET에서 작동합니다
단점 : 자체 스레드에서 실행됩니다
class CancelableDelay
{
Thread delayTh;
Action action;
int ms;
public static CancelableDelay StartAfter(int milliseconds, Action action)
{
CancelableDelay result = new CancelableDelay() { ms = milliseconds };
result.action = action;
result.delayTh = new Thread(result.Delay);
result.delayTh.Start();
return result;
}
private CancelableDelay() { }
void Delay()
{
try
{
Thread.Sleep(ms);
action.Invoke();
}
catch (ThreadAbortException)
{ }
}
public void Cancel() => delayTh.Abort();
}
용법:
var job = CancelableDelay.StartAfter(1000, () => { WorkAfter1sec(); });
job.Cancel(); //to cancel the delayed job
타이머와 이벤트를 사용하는 것 외에 다른 함수의 호출을 지연시키는 표준 방법은 없습니다.
이것은 GUI 안티 패턴이 메소드에 대한 호출을 지연시켜 양식이 배치되었는지 확인할 수있는 것처럼 들립니다. 좋은 생각이 아닙니다.
David O'Donoghue의 답변을 바탕으로 지연된 대의원의 최적화 된 버전이 있습니다.
using System.Windows.Forms;
using System.Collections.Generic;
using System;
namespace MyTool
{
public class DelayedDelegate
{
static private DelayedDelegate _instance = null;
private Timer _runDelegates = null;
private Dictionary<MethodInvoker, DateTime> _delayedDelegates = new Dictionary<MethodInvoker, DateTime>();
public DelayedDelegate()
{
}
static private DelayedDelegate Instance
{
get
{
if (_instance == null)
{
_instance = new DelayedDelegate();
}
return _instance;
}
}
public static void Add(MethodInvoker pMethod, int pDelay)
{
Instance.AddNewDelegate(pMethod, pDelay * 1000);
}
public static void AddMilliseconds(MethodInvoker pMethod, int pDelay)
{
Instance.AddNewDelegate(pMethod, pDelay);
}
private void AddNewDelegate(MethodInvoker pMethod, int pDelay)
{
if (_runDelegates == null)
{
_runDelegates = new Timer();
_runDelegates.Tick += RunDelegates;
}
else
{
_runDelegates.Stop();
}
_delayedDelegates.Add(pMethod, DateTime.Now + TimeSpan.FromMilliseconds(pDelay));
StartTimer();
}
private void StartTimer()
{
if (_delayedDelegates.Count > 0)
{
int delay = FindSoonestDelay();
if (delay == 0)
{
RunDelegates();
}
else
{
_runDelegates.Interval = delay;
_runDelegates.Start();
}
}
}
private int FindSoonestDelay()
{
int soonest = int.MaxValue;
TimeSpan remaining;
foreach (MethodInvoker invoker in _delayedDelegates.Keys)
{
remaining = _delayedDelegates[invoker] - DateTime.Now;
soonest = Math.Max(0, Math.Min(soonest, (int)remaining.TotalMilliseconds));
}
return soonest;
}
private void RunDelegates(object pSender = null, EventArgs pE = null)
{
try
{
_runDelegates.Stop();
List<MethodInvoker> removeDelegates = new List<MethodInvoker>();
foreach (MethodInvoker method in _delayedDelegates.Keys)
{
if (DateTime.Now >= _delayedDelegates[method])
{
method();
removeDelegates.Add(method);
}
}
foreach (MethodInvoker method in removeDelegates)
{
_delayedDelegates.Remove(method);
}
}
catch (Exception ex)
{
}
finally
{
StartTimer();
}
}
}
}
대의원에게 고유 한 키를 사용하여 수업이 약간 더 개선 될 수 있습니다. 첫 번째 발사 전에 동일한 대표단을 두 번째로 추가하면 사전에 문제가 생길 수 있기 때문입니다.
private static volatile List<System.Threading.Timer> _timers = new List<System.Threading.Timer>();
private static object lockobj = new object();
public static void SetTimeout(Action action, int delayInMilliseconds)
{
System.Threading.Timer timer = null;
var cb = new System.Threading.TimerCallback((state) =>
{
lock (lockobj)
_timers.Remove(timer);
timer.Dispose();
action()
});
lock (lockobj)
_timers.Add(timer = new System.Threading.Timer(cb, null, delayInMilliseconds, System.Threading.Timeout.Infinite));
}