在 C# 中使用匿名delegate
s 时,CLR 将在堆上为使用的变量生成本地(例如当前范围内的变量)的副本。对于当前作用域的每个声明变量,这样的局部变量将被放入堆中。
您可以在此示例中看到此行为:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
ThreadPool.QueueUserWorkItem(delegate { execute(i); });
Thread.Sleep(1000);
Console.WriteLine();
for (int i = 0; i < 5; i++)
{
int j = i;
ThreadPool.QueueUserWorkItem(delegate { execute(j); });
}
Thread.Sleep(1000);
}
static void execute(int number)
{
Console.WriteLine(" * NUM=" + number.ToString());
}
}
该程序的输出是(最后 5 个条目的顺序可能会有所不同,而在第一个条目中,也可能得到小于 5 的数字。):
* NUM=5
* NUM=5
* NUM=5
* NUM=5
* NUM=5
* NUM=0
* NUM=1
* NUM=2
* NUM=3
* NUM=4
在方法中调用时,C# 应始终生成本地的新副本。这在本示例中按预期工作:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
call(i);
Thread.Sleep(1000);
}
static void call(int number)
{
ThreadPool.QueueUserWorkItem(delegate { execute(number); });
}
static void execute(int number)
{
Console.WriteLine(" * NUM=" + number.ToString());
}
}
输出:
* NUM=0
* NUM=1
* NUM=2
* NUM=3
* NUM=4
这是有问题的情况:但是,将变量分配给保留区域时它不起作用:stackalloc
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
call(i);
Thread.Sleep(1000);
}
static unsafe void call(int number)
{
int* ints = stackalloc int[64];
ints[32] = number;
ThreadPool.QueueUserWorkItem(delegate { execute(ints[32]); });
}
static void execute(int number)
{
Console.WriteLine(" * NUM=" + number.ToString());
}
}
输出:
* NUM=4
* NUM=4
* NUM=4
* NUM=4
* NUM=4
使用常规局部变量时 - 只需替换call
上面示例中的方法:
static void call(int number)
{
int j = number;
ThreadPool.QueueUserWorkItem(delegate { execute(j); });
}
输出:
* NUM=0
* NUM=1
* NUM=2
* NUM=3
* NUM=4
这种情况使我不信任delegate
C# 中的匿名 s - 因为我不明白 C# 何时不会搞砸我对匿名delegate
s 的调用。
我的问题:为什么 C# 不跟踪stackalloc
有关匿名delegate
s 的空间?我知道 C# 没有跟踪。我想知道为什么它不跟踪,如果它使用常规变量。
我使用 .NET Core 2.1 和 C# 7.3,包括/unsafe
这些示例的开关。