문제

은 거기에 좋은 간단한 방법의 함수 호출을 지연시키는 동안 스레드가 계속 실행?

예:

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));
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top