类型安全控件。调用C#
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了类型安全控件。调用C#相关的知识,希望对你有一定的参考价值。
我正在使用C#编写一个包含2个线程的软件
- 控制窗体(Windows窗体)并与用户连接的线程。
- 一个在后台检查在线数据的线程。
当在线数据不规则时,我需要第二个线程在表格上打印消息。
因为只有创建控件的线程才能更改它,所以我正在使用委托。第二个线程通过Control.Invoke方法调用第一个线程来执行委托。
示例:
public partial class Form1 : Form
{
public delegate void SafeCallDelegate(string text);
public static SafeCallDelegate d;
public Form1()
{
InitializeComponent();
d = new SafeCallDelegate(addText);
}
private static void addText(string text)
{
richTextBox1.Text += text + "
";
}
}
static class Program
{
static Thread secondThread;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
secondThread = new Thread(SecondThreadFunc);
secondThread.Start();
Application.Run(new Form1());
}
static void SecondThreadFunc()
{
int counter = 0;
do
{
if (Form.ActiveForm == null) continue;
Form.ActiveForm.Invoke(Form1.d, new object[] { "SecondThreadFunc counter: " + counter.ToString() });
counter++;
Thread.Sleep(1000);
} while (true);
}
}
我可以使用这个不太干净的解决方案,但是我的问题是这根本不是类型安全的。
Control.Invoke函数接受对象的数组,无论委托要求什么,这都可能导致运行时异常。
是否有使用更类型安全且可以解决我的问题的方法?
谢谢。
答案
据我所知,您希望构建尊重Control Invoke要求的Action <...>或Func <...>委托。如果是这样,您可以像这样装饰现有的通用委托:
public static class InvokeFunc
{
private class InvokeFuncImpl<TRusult>
{
public Func<TRusult> Func { get; }
public InvokeFuncImpl(Func<TRusult> f)
{
Func = f;
}
public static implicit operator Func<TRusult>(InvokeFuncImpl<TRusult> value)
{
return () =>
{
if(Form.ActiveForm == null)
return value.Func();
if(!Form.ActiveForm.InvokeRequired)
return value.Func();
return (TRusult)Form.ActiveForm.Invoke(value.Func);
};
}
}
private class InvokeFuncImpl<TArg1, TRusult>
{
public Func<TArg1, TRusult> Func { get; }
public InvokeFuncImpl(Func<TArg1, TRusult> f)
{
Func = f;
}
public static implicit operator Func<TArg1, TRusult>(InvokeFuncImpl<TArg1, TRusult> value)
{
return (arg) =>
{
if(Form.ActiveForm == null)
return value.Func(arg);
if(!Form.ActiveForm.InvokeRequired)
return value.Func(arg);
return (TRusult)Form.ActiveForm.Invoke(value.Func, arg);
};
}
}
public static Func<TResult> Bulid<TResult>(Func<TResult> f) => new InvokeFuncImpl<TResult>(f);
public static Func<TArg1, TResult> Bulid<TArg1, TResult>(Func<TArg1, TResult> f) => new InvokeFuncImpl<TArg1, TResult>(f);
}
不幸的是,在C#中没有可变参数的泛型参数,因此您应该隐式地使所有泛型重载。
所以您可以编写这样的代码:
_f = InvokeFunc.Bulid((bool x) =>
{
textBox1.Multiline = x;
return textBox1.Text.Length;
});
其中_f是Func类型的某个字段,并且在任何线程中都是安全调用。在实现中,我检查了调用要求,因此,如果不需要,则进行直接调用。
并采取行动<...>:
public static class InvokeAction
{
private class InvokeActionImpl
{
public Action Action { get; }
public InvokeActionImpl(Action a)
{
Action = a;
}
public static implicit operator Action(InvokeActionImpl value)
{
return () =>
{
if(Form.ActiveForm == null)
value.Action();
else if(!Form.ActiveForm.InvokeRequired)
value.Action();
else
Form.ActiveForm.Invoke(value.Action);
};
}
}
private class InvokeActionImpl<TArg1>
{
public Action<TArg1> Action { get; }
public InvokeActionImpl(Action<TArg1> a)
{
Action = a;
}
public static implicit operator Action<TArg1>(InvokeActionImpl<TArg1> value)
{
return (arg) =>
{
if(Form.ActiveForm == null)
value.Action(arg);
else if(!Form.ActiveForm.InvokeRequired)
value.Action(arg);
else
Form.ActiveForm.Invoke(value.Action, arg);
};
}
}
public static Action Bulid<TResult>(Action a) => new InvokeActionImpl(a);
public static Action<TArg1> Bulid<TArg1>(Action<TArg1> a) => new InvokeActionImpl<TArg1>(a);
}
以上是关于类型安全控件。调用C#的主要内容,如果未能解决你的问题,请参考以下文章
WPF应用程序中,调用用户控件时,可以访问到在这个用户控件Xaml代码中的所有内容,这样岂不是不安全?
C#Windowfrom datagridview控件内容怎么在单元格里自动换行全显示出来?
《安富莱嵌入式周报》第279期:强劲的代码片段搜索工具,卡内基梅隆大学安全可靠C编码标准,Nordic发布双频WiFi6 nRF7002芯片