【问题标题】:VB .Net to C# function for controls cross-thread用于控制跨线程的 VB .Net 到 C# 函数
【发布时间】:2022-02-20 10:37:49
【问题描述】:

我正在尝试从 VB 切换。 Net 到 C#(.Net 框架和 .Net &)所以我开始“翻译”一些我很常用的函数。但是我遇到了一些问题(我对基于 C 的语言的线索为零)。

所以,这是我多年来使用的有效 VB .Net 函数,当我从不同的线程、任务等调用控制时,它是一个简单的跨线程解决方案:

Imports System.Linq.Expressions
Imports System.Runtime.CompilerServices

Module Module1

    Private Delegate Sub InvokeThreadSafeMethodDelegate(ByVal Cnt As Control, ByVal Mtd As Expression(Of Action))
    Private Delegate Function InvokeThreadSafeFunctionDelegate(Of T)(ByVal Cnt As Control, ByVal Fnc As Expression(Of Func(Of T))) As T


    <Extension()>
    Public Sub InvokeThreadSafeMethod(ByVal Cnt As Control, ByVal Mtd As Expression(Of Action))
        If (Cnt.InvokeRequired) Then
            Dim Dlg = New InvokeThreadSafeMethodDelegate(AddressOf InvokeThreadSafeMethod)
            Cnt.Invoke(Dlg, Cnt, Mtd)
        Else
            Mtd.Compile().DynamicInvoke()
        End If
    End Sub


    <Extension()>
    Public Function InvokeThreadSafeFunction(Of T)(ByVal Cnt As Control, ByVal Fnc As Expression(Of Func(Of T))) As T
        If (Cnt.InvokeRequired) Then
            Dim Dlg = New InvokeThreadSafeFunctionDelegate(Of T)(AddressOf InvokeThreadSafeFunction)
            Return DirectCast(Cnt.Invoke(Dlg, Cnt, Fnc), T)
        Else
            Return DirectCast(Fnc.Compile().DynamicInvoke(), T)
        End If
    End Function

End Module

我都这样称呼他们:

Me.Label1.InvokeThreadSafeMethod(Sub() Me.Label1.text = "Test")

Dim X as String = Me.Label1.InvokeThreadSafeFunction(Function() Me.Label1.text)

将它翻译成 C# 后,我得到了这个:

using System.Linq.Expressions;

internal static class Cls_Comune
{

    private delegate void InvokeThreadSafeMethodDelegate(Control C, Expression<Action> M);
    private delegate T InvokeThreadSafeFunctionDelegate<T>(Control C, Expression<Func<T>> F);

    public static void InvocaMetodoSicuro(this Control C, Expression<Action> M)
    {
        if (C.InvokeRequired)
        {
            var D = new InvokeThreadSafeMethodDelegate(InvocaMetodoSicuro);
            C.Invoke(D, C, M);
        }
        else
            M.Compile().DynamicInvoke();
    }

    public static T InvocaFunzioneSicuro<T>(this Control C, Expression<Func<T>> F)
    {
        if (C.InvokeRequired)
        {
            var D = new InvokeThreadSafeFunctionDelegate<T>(InvocaFunzioneSicuro);
            return (T)C.Invoke(D, C, F);
        }
        else
            return (T)F.Compile().DynamicInvoke();
    }
}

在这里,在return (T)F.Compile().DynamicInvoke(); 这一行中,我收到关于 Null 变量转换的错误。在 VB .Net 中,我使用了 C# 中似乎不存在的 Directcast。 但主要问题是,我怎么能打电话给他们?因此,给我 2 个不同的错误:

private async void Naviga(string strLnk)
        {
            await Task.Run(void () =>
            {
                Txt_Stato.InvocaMetodoSicuro(() => Txt_Stato.Text = "Test");

                WW2.InvocaMetodoSicuro(() => WW2.Source = new System.Uri(strLnk, UriKind.Absolute));

                string str = WW2.InvocaFunzioneSicuro(() => WW2.Source.ToString());
            }

            );
        }

在任务中,第一行 (Txt_Stato) 给我“InvocaMetodoSicuro 不是 ToolStripLabel 的一部分”。因为它不能从 stati 类中获取扩展名。第二行(WW2 是 WebView2)给我“表达式树可能不包含赋值运算符”。 第三行(字符串 str...)没有给我任何错误,但我不知道是否有效,因为静态类中的“空错误”导致调试无法启动。

再次,我正在尝试通过自学从 VB .Net 切换到 C#,并且我想转换一些我在 VB .Net 中拥有的有用功能。因此,如果 C# 是一团糟,请认为我 2 小时前才开始使用它进行编码。 那么,代码有什么问题呢?

【问题讨论】:

  • 以下内容可能会有所帮助:stackoverflow.com/questions/8983137/…
  • @user9938 是的,谢谢。这有助于我修复第一个函数,即我发送控件和 void 的函数,但不是第二个函数,其中必须是函数而不是 void。为了让您更好地理解,在 Tanks 中,前 2 个代码(Txt_StatoWW2)现在有效,但 string str = ... 无效,因为它不是空的。

标签: c# vb.net multithreading async-await task


【解决方案1】:

我不知道你为什么使用Expression&lt;Action&gt;Expression&lt;Func&lt;T&gt;&gt;ActionFunc&lt;T&gt; 就足够了。你没有以任何有意义的方式使用Expression&lt;&gt;

您的代码可以简单地改写为:

public static void InvocaSicuro(this Control C, Action M)
{
    if (C.InvokeRequired)
        C.Invoke(M);
    else
        M();
}

public static T InvocaSicuro<T>(this Control C, Func<T> F) =>
    C.InvokeRequired
    ? C.Invoke(F)
    : F();

您甚至可以重复使用相同的名称(就像我所做的那样),因为方法重载可以为您解决所有问题。

我建议更进一步并添加以下签名:

public static void InvocaSicuro<C>(this C control, Action<C> action) where C : Control
{
    if (control.InvokeRequired)
        control.Invoke(() => action(control));
    else
        action(control);
}

public static T InvocaSicuro<C, T>(this C control, Func<C, T> func) where C : Control =>
    control.InvokeRequired
    ? control.Invoke(() => func(control))
    : func(control);

这些版本是针对调用控件调用的,使重构更加安全,并且减少了重复。

例如,这个:

Txt_Stato.InvocaSicuro(() => Txt_Stato.Text = "Test");

...变成:

Txt_Stato.InvocaSicuro(c => c.Text = "Test");

上述代码在 .NET 6.0 中运行良好,因为核心中添加了新的 Invoke 重载。

对于 4.7.2,您需要以下代码:

public static void InvocaSicuro(this Control control, Action action)
{
    if (control.InvokeRequired)
        control.Invoke(action);
    else
        action();
}

public static T InvocaSicuro<T>(this Control control, Func<T> func) =>
    control.InvokeRequired
    ? (T)control.Invoke((Delegate)func)
    : func();

public static void InvocaSicuro<C>(this C control, Action<C> action) where C : Control
{
    if (control.InvokeRequired)
        control.Invoke((Action)(() => action(control)));
    else
        action(control);
}

public static T InvocaSicuro<C, T>(this C control, Func<C, T> func) where C : Control =>
    control.InvokeRequired
    ? (T)control.Invoke((Action)(() => func(control)))
    : func(control);

【讨论】:

  • 是的,可以,谢谢!我有一些问题,DynamicInvoke 不是比 Invoke 更好吗?而且,我如何将这些功能用于子控件?我的意思是,假设我想在 ToolStrip1 中更改 ToolStripLabel1 的文本,我现在不能,因为如果我像 ToolStripLabel1.InvocaSicuro(c =&gt; c.Text = "Test"); 这样使用它们将不起作用,因为我应该调用 ToolStrip1,但 ToolStrip1.InvocaSicuro(c =&gt; c.Text = "Test"); 不会更改 Label1 或 LabelN 文本。
  • @Tyler - 这是关于InvokeDynamicInvoke 的讨论。
  • @Tyler - 我建议你添加这两个额外的签名 - 我没有说你应该删除前两个。前两个仍然有它们的用途。
  • 我明白了。无论如何,我已经在一个库项目中添加了这两个代码,现在都给了我错误(而在正常形式的项目中它们工作)。错误是this。我已经用control.Invoke((Action)(() =&gt; action(control))); 解决了action 一个,但是关于func 一个,我不知道如何解决,也在网上寻找。 (从 VB .Net 到 C# 的过渡非常痛苦)
  • 我测试了我发布的所有代码,它运行良好。你能给我一个证明问题的minimal reproducible example吗?
猜你喜欢
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-10
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多