在具有委托使用的多线程winform应用程序中,什么被认为是良好的编程实践

本文关键字:什么 认为是 编程 应用程序 winform 多线程 | 更新日期: 2023-09-27 17:57:52

我正在修改一个用C#编写的应用程序,该应用程序大量使用多线程来向用户播放音频文件和显示图像。考虑到它是多线程的,我需要经常使用Invoke方法来更改表单元素。我遇到了一种我不太适应的模式,我发现自己经常写一些小的委托方法,通常只做一件事。一个例子如下:

delegate void setImageCallback(Image img);
private void setImage(Image img)
{
    this.pictureBox1.Image = img;
}
private void someOtherMethod()
{
    ...
    if (this.pictureBox1.InvokeRequired)
    {
        this.Invoke(new setImageCallback(setImage), Image.FromFile("example.png");
    }
    else
    {
        this.pictureBox1.Image = Image.FromFile("example.png");
    }
    ...
}

人们通常是如何处理这些情况的,这样你就不会发现自己为了保持线程安全而写了大量的委托和方法?显然,类似方法的合并是很好的,但如果我可能需要更新表单上的每个表单元素,我不想为每个方法都有一个"修改"委托和方法。

谢谢。

在具有委托使用的多线程winform应用程序中,什么被认为是良好的编程实践

这里有一个很好的例子。

this.BeginInvoke( (Action) (()=>
    {
        pictureBox1.Image = Image.FromFile("example.png");
    }));

您绝对不需要为每一个单独的委托。您可以使用Action委托和lambda表达式来简化它,如下所示:

private void SomeOtherMethod()
{
    Action action = () => pictureBox1.Image = Image.FromFile("example.png");
    if (pictureBox1.InvokeRequired)
    {
        Invoke(action);
    }
    else
    {
        action();
    }
}

或者,您可以将if语句和InvokeRequired检查分离出来,并对其进行进一步的推广,如下所示:

public static void InvokeIfRequired(Control control, Action action)
{
    if (control.InvokeRequired)
    {
        control.Invoke(action);
    }
    else
    {
        action();
    }
}
private void SomeOtherMethod()
{
    InvokeIfRequired(() => pictureBox1.Image = Image.FromFile("example.png");
}

我会将MethodInvoker类型与匿名方法或lambda表达式结合使用。我还将调用逻辑构建到方法本身中,而不是使用单独的线程安全方法:

void SomeMethod(/* with whatever args */) {
    if (InvokeRequired)
        Invoke(new MethodInvoker(() => SomeMethod(/* args used to call method */)));
    else
        // the method body itself
}