VB .Net 到 C# 函数,用于控制跨线程
VB .Net to C# function for controls cross-thread
我正在尝试从 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 class 获取扩展名。第二行(WW2 是 WebView2)给我“表达式树可能不包含赋值运算符。”
第三行(string str ...)没有给我任何错误,但我不知道是否有效,因为静态 class.
中的“空错误”导致调试无法启动
同样,我正在尝试通过自学从 VB .Net 切换到 C#,并且我想转换我在 VB .Net 中拥有的一些有用功能。所以,如果 C# 是一团糟,请认为我 2 小时前才开始用它编写代码。
那么,代码中的问题是什么?
我不知道你为什么使用 Expression<Action>
和 Expression<Func<T>>
而 Action
和 Func<T>
就足够了。您没有以任何有意义的方式使用 Expression<>
。
您的代码可以简单地重写为:
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();
您甚至可以 re-use 使用相同的名称(就像我所做的那样),因为方法重载可以为您解决所有问题。
我建议更进一步并添加以下签名:
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);
我正在尝试从 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 class 获取扩展名。第二行(WW2 是 WebView2)给我“表达式树可能不包含赋值运算符。” 第三行(string str ...)没有给我任何错误,但我不知道是否有效,因为静态 class.
中的“空错误”导致调试无法启动同样,我正在尝试通过自学从 VB .Net 切换到 C#,并且我想转换我在 VB .Net 中拥有的一些有用功能。所以,如果 C# 是一团糟,请认为我 2 小时前才开始用它编写代码。 那么,代码中的问题是什么?
我不知道你为什么使用 Expression<Action>
和 Expression<Func<T>>
而 Action
和 Func<T>
就足够了。您没有以任何有意义的方式使用 Expression<>
。
您的代码可以简单地重写为:
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();
您甚至可以 re-use 使用相同的名称(就像我所做的那样),因为方法重载可以为您解决所有问题。
我建议更进一步并添加以下签名:
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);