它类似于许多问题,但不是很狡猾。对于Winforms我需要BeginInvoke
之类的内容,但不仅仅适用于winforms。所以我需要单一方法,适用于任何类型的应用程序,所以我正在调用
void ExecuteInMainContext(Action action)
{
...
}
它应该可以工作,从Console,winforms,wpf等调用。我看到的所有方法都是使用BeginInvoke
用于winforms,Dispatcher.Invoke
用于WPF等。但是我应该从库中调用它,我不知道从哪里调用它。并且它也应该对调用代码是透明的,所以它不应该传递像指向调用主线程等的东西,lib应该从环境中获取此信息,而不是从用户代码中获取,当然也没有任何全局变量。
我尝试使用Task.ConfigureAwait
,但没有帮助。
我找到了这个
在控制台应用程序中,您无法执行此操作(无需大量工作)。内置到TPL中用于将调用封送回线程的机制都依赖于具有已安装的SynchronizationContext的线程。这通常由用户界面框架安装(即:Windows窗体中的Application.Run,或WPF的启动代码等)。
但我希望这是可能的。
测试代码:
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();
}
}
}
所以它应该在任何地方写相同的数字。
答案 0 :(得分:6)
试试这个
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();
}