我需要调用符合以下条件的方法。
我有一个原型实现,使用以下设计来满足此标准。
假设存在Form
且包含Panel
。
IntegerInput
课程为UserControl
,TextBox
和Button
。
public partial class IntegerInput : UserControl
{
public TaskCompletionSource<int> InputVal = new TaskCompletionSource<int>(0);
public IntegerInput()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int val = 0;
Int32.TryParse(textBox1.Text, out val);
InputVal.SetResult(val);
}
}
Form1UserInput
类由Form1
实例化。在提供给调用类之前,container
是由Panel
设置的Form1
。
public interface IUserInput
{
Task<int> GetInteger();
}
public class Form1UserInput : IUserInput
{
public Control container;
private IntegerInput integerInput = new IntegerInput();
public IntegerInput IntegerInput { get { return integerInput; } }
public async Task<int> GetInteger()
{
container.Invoke(new Action(() =>
{
container.Controls.Clear();
container.Controls.Add(integerInput);
}));
await integerInput.InputVal.Task;
return integerInput.InputVal.Task.Result;
}
}
Demo
类包含我想要调用的方法。
public class Demo
{
public IUserInput ui;
public async void MethodToInvoke()
{
// Interface with hardware...
// Block waiting on input
int val = await ui.GetInteger();
// Interface with hardware some more...
}
public async void AnotherMethodToInvoke()
{
// Interface with hardware...
// Block waiting on multiple input
int val1 = await ui.getInteger();
int val2 = await ui.getInteger();
// Interface with hardware...
}
}
这是调用类的外观的大致轮廓。对Task.Run()
的调用对我的原型来说是准确的。
public class Invoker
{
public async Task RunTestAsync(IUserInput ui)
{
object DemoInstance = Activator.CreateInstance(typeof(Demo));
MethodInfo method = typeof(Demo).GetMethod("MethodToInvoke");
object[] args = null;
((IUserInput)DemoInstance).ui = ui;
var t = await Task.Run(() => method.Invoke(DemoInstance, args));
// Report completion information back to Form1
}
}
Form1
控制器类实例Invoker
并调用传递RunTestAsync
实例的Form1UserInput
。
我知道可能会阻止长期运行的任务以及对ThreadPool
资源意味着什么的一些问题。但是,我正在构建的应用程序不提供一次调用多个方法的能力。当被调用的方法正在运行时,应用程序可能提供一些其他有限的功能,但当前的要求没有详细指定这样的功能。我预计在任何时候都只会有一个长时间运行的线程。
是否使用Task.Run()为这种类型的方法调用合理的实现?如果没有,那么提供所需标准的更合理的实施是什么?我应该考虑ThreadPool之外的专用线程来进行此调用吗?
答案 0 :(得分:1)
对这种类型的方法调用使用Task.Run()是否合理实现?
假设您的&#34;界面与硬件&#34;只能使用同步 API来完成,然后是的,Task.Run
就可以了。
但是,当被调用时,我会更改。现在,Task.Run
正在包装一个在线程池上执行的async void
方法(并使用Invoke
跳回UI线程)。这些都是有问题的:Task.Run
超过async void
似乎会完成&#34;早期&#34; (即在第一个await
);使用Invoke
表示正在进行紧密耦合(UI调用后台服务调用UI)。
我会将async void
替换为async Task
并更改Task.Run
用于避免Invoke
的位置:
public async Task<int> GetInteger()
{
container.Controls.Clear();
container.Controls.Add(integerInput);
// Note: not `Result`, which will wrap exceptions.
return await integerInput.InputVal.Task;
}
public async Task MethodToInvokeAsync()
{
await Task.Run(...); // Interface with hardware...
// Block waiting on input
int val = await ui.GetInteger();
await Task.Run(...); // Interface with hardware some more...
}
var t = await (Task)method.Invoke(DemoInstance, args);