使用ParameterizedThreadStart委托创建的Thread可以调用Start(Object)传参,当方法不具有与ParameterizedThreadStart兼容的签名和返回类型时,需要对方法进行封装,其中就包括如何处理返回值和out/ref参数的问题。
比如在线程中要执行下面的方法
public static string testFunc (ref double a, int b, out double c)
{
double d = a + 0.01;
c = d;
string s = "a=" + a + ";b=" + b + ";c=" + d;
a = a + b;
return s;
}
可以看出.NET自带的委托(Action,Func,Predicate)都不适用于testFunc,下面自己声明一个委托
public delegate string TestDelegate (ref double a, int b, out double c);
在实例化Thread的时候不直接把testFunc传过去,在传过去的匿名函数中被调用的是一个以testFunc作为参数的Action<TestDelegate>实例,而这个实例作为参数在Thread.Start中传入,对testFunc的调用及其参数和返回值的处理写在这个Action<TestDelegate>实例之中。
static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
testThread ();
Thread.Sleep (1000);
Console.WriteLine (s);
}
public static void testThread ()
{
double a = 3.5, c;
int b = 1;
string s = string.Empty;
Thread thread = new Thread ((object parameter) => {
Action<TestDelegate> p = parameter as Action<TestDelegate>;
if (p != null) {
p (testFunc);
}
});
thread.Start ((TestDelegate start) => s = start (ref a, b, out c));
}
然后按上面的方法封装成一个泛型Thread如下
class Thread<TStart> /* where TStart : Delegate */ // 约束不能是特殊类“System.Delegate”
{
Thread originalThread;
public Thread OriginalThread { get { return originalThread; } }
public Thread (TStart start)
{
originalThread = new Thread (convertStart (start));
}
public Thread (TStart start, int maxStackSize)
{
originalThread = new Thread (convertStart (start), maxStackSize);
}
ParameterizedThreadStart convertStart (TStart start)
{
return (object parameter) => {
Action<TStart> p = parameter as Action<TStart>;
if (p != null) {
p (start);
}
};
}
public void Start (Action<TStart> parameter)
{
originalThread.Start (parameter);
}
}
在Main中加入调用代码
static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
testThread ();
Thread.Sleep (1000);
Console.WriteLine (s);
double a = 3.5, c;
int b = 1;
string s = string.Empty;
Thread<TestDelegate> thread = new Thread<TestDelegate> (testFunc);
thread.Start ((TestDelegate start) => {
for (int i = 1; i < 10; i++) {
s = start (ref a, 2, out c);
Console.WriteLine (s);
Thread.Sleep (1000);
}
});
for (int i = 1; i < 10; i++) {
Console.WriteLine ("Hello World!");
Thread.Sleep (1000);
}
}
下面被注释的语句报编译器错误CS1628“不能在匿名方法、lambda 表达式或查询表达式内使用 ref 或 out 参数”
public static string testThread (ref double a, int b, out double c)
{
string s = string.Empty;
Thread<TestDelegate> thread = new Thread<TestDelegate> (testFunc);
// thread.Start ((TestDelegate start) => s = start (ref a, b, out c));
double a1 = a, c1 = default(double);
thread.Start ((TestDelegate start) => s = start (ref a1, b, out c1));
c = c1;
return s;
}
而值参数和局部变量方式则没有这个限制,这涉及到C#的闭包。