Task[] task = new Task[count];
for (int i = 0; i < count; i++)
{
myModel my = new myModel();
my.id = "ID:" + i.ToString();
my.name = "姓名:" + i.ToString();
my.age = "性别:" + i.ToString(); int a = i;
task[i] = new Task(()=> {
list1.Add(i.ToString()); // 为什么这个I都是一样的
list1.Add(a.ToString()); // 这个就是正常的循环值
list_model.Add(my);
});
task[i].Start();
}
解决方案 »
- 谁能一句话说说啥是SQL BI,干啥的时候用它?想大概了解下
- Remoting问题
- Socket服务端C#编程
- 求页面中指定用户按回车键后要执行的按钮的方法?
- 【求助】有没有可以缩放图形的控件或者提供一些建议
- 请问一下怎样把有SPLIT这个函数得到的字符存到一个二维数组中?
- c#如何绕过打印机驱动程序向打印机端口发字符串进行打印?内有VB的代码,谁翻译一下
- 用socket传送较大数据,怎么做,谢谢大家!
- dexplore.exe总出错,一打开就说内存地址错误!兄弟们救命阿!请思归代表微软官方回答
- 如何重写自定义控件的load事件或init事件???
- 问一个有关重复启动C#编写的exe和传参问题
- 自学C#新人遇到问题,求大佬帮忙解决
Thread.Sleep(50);
list1.Add(i.ToString()); // <span style="color: #FF00FF;"> 为什么这个I都是一样的</span>
list1.Add(a.ToString()); // <span style="color: #FF0000;">这个就是正常的循环值</span>
list_model.Add(my);
});线程中等一会再看看?
哇,神速。感谢。
一样的,早试过了。还是有BUG。起初以为是 值类型和引用类型的问题,但是发现不是,很奇怪才特意过来发帖。
你可以在本地运行下看看。
task[i].Wait();
楼主再测一下framework 4.5之后的版本,应该结果是不一样的。
委托
匿名委托
Lambda表达式。
这个和委托没关系。i 赋值给 任何引用类型或值类型后都是正常的递增,为什么直接取 i 值 就是恒定不变的呢。
委托
匿名委托
Lambda表达式。
这个和委托没关系。i 赋值给 任何引用类型或值类型后都是正常的递增,为什么直接取 i 值 就是恒定不变的呢。这个和是否值类型无关。是因为你创建了新的线程,这样代码并不是按写的顺序执行的。
多线程用的少,不好掌握,容易出现奇怪的BUG。
new Task(()=> {
list1.Add(i.ToString()); // 为什么这个I都是一样的
list1.Add(a.ToString()); // 这个就是正常的循环值
list_model.Add(my);
}); 你开启了多线程 在执行的时候 for 循环已经执行不知道到哪里了。 如果count 足够大的话i 就不一定是count 而是远大于a的一个值。
list1.Add(a.ToString()); // 这个就是正常的循环值
list_model.Add(my);
在执行这三句话的时候 跟for循环中的i 在时间顺序上已经没有任何关系了,只是用了同一个变量而已。
编译器会把lambda表达式编译成一个匿名类,从lambdal表达式外部传入的变量,会成为类的字段,
匿名类里面还有一个委托,
for (int i = 0; i < count; i++)
{
myModel my = new myModel();
my.id = "ID:" + i.ToString();
my.name = "姓名:" + i.ToString();
my.age = "性别:" + i.ToString();
int a = i;
task[i] = new Task(()=> {
list1.Add(i.ToString()); // <span style="color: #FF00FF;"> 为什么这个I都是一样的</span>
list1.Add(a.ToString()); // <span style="color: #FF0000;">这个就是正常的循环值</span>
list_model.Add(my);
});
task[i].Start();
}==>
for内部的这些语句,几乎是瞬间完成的,此时I值是count,也就是说每个task输出的I值,都是count
而a不同,a暂存了I的值,后面,没有谁改变它的值
这种代码很可怕,调用线程(一般是主线程)“瞬间”执行完,很可能开出的多个子线程才正在运行,这样我们知道I值是count,也算是可控的;
但是,如果一个次线程提前执行完,其他次线程没有,输出结果就不都是count了,可能是count-1,或-2
你在循环中 int a = i; 创建 count 个临时变量,每个 a 都在生存周期内传递给了 TaskC# 继承了 C 的不良习惯:函数(过程)体内可不加声明的使用体外的变量,这容易把人绕晕
如果显式的传递参数,或是声明某个变量是体外定义的,就将很清晰了