它类似于许多问题,但不是很狡猾.我需要类似于
Winforms的BeginInvoke,但不仅仅适用于winforms.所以我需要单一的方法,适用于任何类型的应用程序,所以我打电话
void ExecuteInMainContext(Action action) { ... }
它应该工作,从控制台,winforms,Wpf等调用.我看到的所有方法都是使用BeginInvoke for winforms,Dispatcher.Invoke for WPF等.但我应该从库中调用它,我不知道从哪里调用它.并且它也应该对调用代码是透明的,因此它不应该传递类似于调用主线程等的指针,lib应该从环境中获取此信息,而不是从用户代码获取,当然也没有任何全局变量.
我试过使用Task.ConfigureAwait,但它没有帮助.
我发现了这个
You can’t do this (without a lot of work) in a Console application. The mechanisms built into the TPL for marshaling the call back onto a thread all rely on the thread having an installed SynchronizationContext. This typically gets installed by the user interface framework (ie: Application.Run in Windows Forms,or in WPF’s startup code,etc).
但我希望这是可能的.
测试代码:
using System; using System.Threading; namespace Test { class Program { private static void Main(string[] args) { Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId); Publisher publisher = new Publisher(Method); Console.ReadLine(); } private static void Method(string s) { Console.WriteLine(s + " " + Thread.CurrentThread.ManagedThreadId); } } class Publisher { public event Action<string> Action; protected virtual void OnAction(string obj) { Action<string> handler = Action; if (handler != null) { SafeCall(() => handler(obj)); } } private static void SafeCall(Action action) { // ??? action(); // should write 1 } public Publisher(Action<string> action) { Action = action; Console.WriteLine("Publisher thread: " + Thread.CurrentThread.ManagedThreadId); Thread thread = new Thread(() => OnAction("hello")); thread.Start(); } } }
所以应该在任何地方写相同的数字.
解决方法
试试这个
void ExecuteInMainContext(Action action) { var synchronization = SynchronizationContext.Current; if (synchronization != null) { synchronization.Send(_ => action(),null);//sync //OR synchronization.Post(_ => action(),null);//async } else Task.Factory.StartNew(action); //OR var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task task = new Task(action); if (scheduler != null) task.Start(scheduler); else task.Start(); }