我遇到了一个关于C#的有趣问题.我有如下代码.
List<Func<int>> actions = new List<Func<int>>();
int variable = 0;
while (variable < 5)
{
actions.Add(() => variable * 2);
++ variable;
}
foreach (var act in actions)
{
Console.WriteLine(act.Invoke());
}
Run Code Online (Sandbox Code Playgroud)
我希望它输出0,2,4,6,8.但是,它实际输出5个10.
似乎是由于所有操作都涉及一个捕获的变量.结果,当它们被调用时,它们都具有相同的输出.
有没有办法解决这个限制,让每个动作实例都有自己的捕获变量?
假设我的对象处于完美的工作状态(即TDD让我觉得它们有效).
我有一个我这样创建的列表(正确缩进除外):
var result = from v in vendors
from p in v.Products
orderby p.Name
select p;
Run Code Online (Sandbox Code Playgroud)
这有效 - 我从所有供应商处获得所有产品.
现在我有一个条件列表,由用户在运行时构建.让我们应用它们:
foreach (Attribute a in requiredAttributes)
{
result = result.Where(p => p.Attributes.Contains(a));
}
Run Code Online (Sandbox Code Playgroud)
这可能是原始的,但我认为它有用.但是,在完成此foreach循环之后,当您枚举"result"时,它将包含其Attributes属性(也是集合)中具有requiredAttributes集合的LAST属性的所有产品.
对我来说,这种气味就像"a"被覆盖在某个地方,每次旅行通过循环,只有最后一个适用.
如果没有以某种方式将扩展方法写入IEnumerable,称为ContainsAll(IEnumerable)或其他类似的东西,我怎么能实现我想要的,这基本上是一个逻辑AND,只给我那些具有所有必需属性的产品?
我正在使用jQuery,我有一个我不明白的奇怪的事情.我有一些代码:
for (i = 1; i <= some_number; i++) {
$("#some_button" + i).click(function() {
alert(i);
});
}
Run Code Online (Sandbox Code Playgroud)
正如名字所说的"#some_button" - 它们是一些按钮.点击它们时,应该弹出一个带有它号码的方框,对吗?但他们没有.如果有4个按钮,它们总是弹出"5"(按钮计数+ 1).为什么会这样?
这可以在for循环中完成吗?
TickEventArgs targs1 = new TickEventArgs(lbl1_up_time, _elapsedTime_up1);
timer_up1.Tick += (sender, e) => Tick(targs1);
TickEventArgs targs2 = new TickEventArgs(lbl2_up_time, _elapsedTime_up2);
timer_up2.Tick += (sender, e) => Tick(targs2);
TickEventArgs targs3 = new TickEventArgs(lbl3_up_time, _elapsedTime_up3);
timer_up3.Tick += (sender, e) => Tick(targs3);
TickEventArgs targs4 = new TickEventArgs(lbl4_up_time, _elapsedTime_up4);
timer_up4.Tick += (sender, e) => Tick(targs4);
TickEventArgs targs5 = new TickEventArgs(lbl5_up_time, _elapsedTime_up5);
timer_up5.Tick += (sender, e) => Tick(targs5);
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为我超出界限(5)
targs[0] = new TickEventArgs(lbl1_up_time, _elapsedTime_up1);
targs[1] = new TickEventArgs(lbl2_up_time, _elapsedTime_up2);
targs[2] = new TickEventArgs(lbl3_up_time, _elapsedTime_up3);
targs[3] = new …Run Code Online (Sandbox Code Playgroud) 此函数用于返回用户搜索输入的联系人列表.搜索词的数量始终至少为一,但可能很多.
public IList<Contact> GetContacts(string[] searchTerms)
{
using (dbDataContext db = new dbDataContext())
{
var contacts = from _contacts in db.Contacts
orderby _contacts.LastName ascending, _contacts.FirstName ascending
select _contacts;
foreach (string term in searchTerms)
{
contacts = (IOrderedQueryable<Contact>)contacts.Where(x => SqlMethods.Like(x.FirstName, "%" + term + "%")
|| SqlMethods.Like(x.MiddleName, "%" + term + "%")
|| SqlMethods.Like(x.LastName, "%" + term + "%")
|| SqlMethods.Like(x.PreferredName, "%" + term + "%"));
}
return contacts.ToList<Contact>();
}
}
Run Code Online (Sandbox Code Playgroud)
问题出在循环中.即使生成的sql看起来是正确的,也只使用了最后一个搜索词(就像为术语数生成了正确数量的子句一样).
示例 - 如果我传递两个术语('andr','sm'),生成的sql显示两个子句块,但只使用'sm'作为两个块中的param.
我究竟做错了什么?我应该使用SqlMethods吗?
我在VB.NET中使用LINQ,有时我会遇到类似的查询
For i = 0 To 10
Dim num = (From n In numbers Where n Mod i = 0 Select n).First()
Next
Run Code Online (Sandbox Code Playgroud)
然后它会出现警告" 在lambda表达式中使用迭代变量可能会产生意外结果.相反,在循环中创建一个局部变量并为其赋值迭代变量的值."
我知道在lambda表达式中使用迭代变量不是一个好习惯,因为只在需要时才计算lambda表达式.(这个问题是关于那个)
现在我的问题是,如何在使用First(),Single(),ToList()等结构对就地计算表达式的情况下抑制此警告(这只是一个警告,但我喜欢我的代码清理.)
(声明一个局部变量并将迭代变量传递给它是一个选项,但我正在寻找一个干净的解决方案.)
我正在使用.Net 3.5上的Reactive Extensions库的任务部分
它大部分工作顺利,但在一个地方它调用相同的任务两次.
电话看起来像这样:
Task.Factory.StartNew(
() => Processor.ProcessMessage(incomingMessage),
TaskCreationOptions.PreferFairness );
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?这是一个错误吗?
----更新
我认为问题在于c#在lambdas中关闭的方式.问题不在TPL中,与普通旧线程池一起返回同样的问题.
这解决了它:
foreach (var Processor in processors)
{
object[] crap = new object[2];
crap[0] = Processor;
crap[1] = incomingMessage;
Task.Factory.StartNew(Magic, crap, TaskCreationOptions.PreferFairness);
}
public void Magic(object obj)
{
object[] crap =(object[]) obj;
((IIncomingMessageProcessor)crap[0]).ProcessMessage((IncomingMessageBase)crap[1]);
}
Run Code Online (Sandbox Code Playgroud)
原始来源是:
foreach (var Processor in processors)
{
Task.Factory.StartNew(
() => Processor.ProcessMessage(incomingMessage),
TaskCreationOptions.PreferFairness );
}
Run Code Online (Sandbox Code Playgroud)
所以我在处理器周围关闭,我想问题是它为lambda回收相同的对象并交换处理器.
----更新2
我确信这是问题所在.我在创建任务时重构和调试了System.Threading.dll,它是使用相同的委托(Same ObjectID)创建的,并且处理器在迭代之间的Target属性中发生了变化.谁知道一个好的工作?
----更新3这也有效(感谢Judah Himango):
foreach (var processor in processors)
{
var crap = processor;
Task.Factory.StartNew(() => crap.ProcessMessage(incomingMessage), …Run Code Online (Sandbox Code Playgroud) 可能重复:
为什么在lambda表达式中使用迭代变量是不好的
为什么我会得到:"lambda表达式中的迭代变量可能会产生意外结果"?假设我有以下代码:
Dim writeAbleColumns As String() = {"IsSelected", "IsFeeExpense", "IsSubscriptionRedemption"}
With grid
For Each column As DataGridViewColumn In .Columns
column.ReadOnly = Not Array.Exists(writeAbleColumns, Function(arrElement) column.Name = arrElement)
Next
End With
Run Code Online (Sandbox Code Playgroud)
我收到警告:
Warning 1 Using the iteration variable in a lambda expression may have unexpected results. Instead, create a local variable within the loop and assign it the value of the iteration variable.
Run Code Online (Sandbox Code Playgroud)
我不明白为什么将我的代码更改为以下更改:
Dim writeAbleColumns As String() = {"IsSelected", "IsFeeExpense", "IsSubscriptionRedemption"}
With grid
For Each column As DataGridViewColumn In …Run Code Online (Sandbox Code Playgroud) class Thread1_8
{
static int shared_total;
static int thread_count;
static readonly object locker = new object();
static void Main()
{
int[,] arr = new int[5, 5] { { 1,2,3,4,5}, {5,6,7,8,9}, {9,10,11,12,13}, {13,14,15,16,17}, { 17,18,19,20,21} };
for(int i = 0; i < 5; i++)
{
new Thread(() => CalcArray(i, arr)).Start();
}
while(thread_count < 5)
{
}
Console.WriteLine(shared_total);
}
static void CalcArray(int row, int[,] arr)
{
int length = arr.GetLength(0);
int total = 0;
for(int j = 0; j < length; j++) …Run Code Online (Sandbox Code Playgroud) 考虑以下lua代码:
f = {}
for i = 1, 10 do
f[i] = function()
print(i .. " ")
end
end
for k = 1, 10 do
f[k]()
end
Run Code Online (Sandbox Code Playgroud)
这将打印从1到10的数字.在这种情况下,i将关闭外部循环的每次迭代的值.这就是我一直都懂得闭合的方式,我很开心......
...直到我将一些lua代码移植到c#中,我试图做同样的事情:
var f = new Action[10];
for (int i = 0; i < 10; i++)
{
f[i] = (new Action(delegate()
{
Console.Write(i + " ");
}));
}
for (int k = 0; k < 10; k++)
{
f[k]();
}
Run Code Online (Sandbox Code Playgroud)
现在我将10号打印10次(让我们忘记了lua数组是基于1的).实际上,在这种情况下,闭包对变量起作用,而不是它的值,这很有意义,因为我只是在第一个循环结束后调用函数.
JavaScript似乎具有相同的语义(接近变量):
var f = []
for (var i = 0; …Run Code Online (Sandbox Code Playgroud) 我真的不太了解任务和线程.我在嵌套的三个级别中有一个方法for,我希望在不同的线程/任务中多次运行,但是我传递给方法的变量变得疯狂,让我用一些代码解释一下:
List<int> numbers=new List<int>();
for(int a=0;a<=70;a++)
{
for(int b=0;b<=6;b++)
{
for(int c=0;b<=10;c++)
{
Task.Factory.StartNew(()=>MyMethod(numbers,a,b,c));
}
}
}
private static bool MyMethod(List<int> nums,int a,int b,int c)
{
//Really a lot of stuff here
}
Run Code Online (Sandbox Code Playgroud)
这是嵌套,myMethod确实做了很多事情,比如计算一些数字的阶乘,写入不同的文档和匹配响应与组合列表并调用其他小方法,它也有一些返回值(布尔值),但我此刻不要关心他们.问题是没有任务达到目的,就像每次嵌套调用它自己刷新的方法一样,删除以前的实例.它还会给出一个错误,"尝试除以0",其值超过由FORs分隔的值,例如a=71, b=7, c=11所有变量都为空(这就是除以零的原因).我真的不知道如何解决它.