我的一个朋友和我正在讨论什么是JS的封闭,什么不是.我们只是想确保我们真正理解它.
我们来看看这个例子吧.我们有一个计数循环,并希望在控制台上打印计数器变量延迟.因此,我们使用setTimeout和闭包来捕获计数器变量的值,以确保它不会打印值N的N倍.
错误的解决方案,无需关闭或接近任何倒闭将是:
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
Run Code Online (Sandbox Code Playgroud)
这当然会打印10次i循环后的值,即10.
所以他的尝试是:
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2);
}, 1000)
})();
}
Run Code Online (Sandbox Code Playgroud)
按预期打印0到9.
我告诉他,他并没有使用封闭捕获i,但他坚持认为他是.我证明他没有使用闭包,将for循环体放在另一个setTimeout(将他的匿名函数传递给setTimeout),再次打印10次10.如果我将他的函数存储在a中var并在循环之后执行它同样适用,也打印10次10.所以我的论点是他并没有真正捕获它的值i,使他的版本不是一个闭包.
我的尝试是:
for(var i = 0; i < …Run Code Online (Sandbox Code Playgroud) 这是Access到Modified Closure的问题扩展.我只是想验证以下内容是否足够安全,适合生产使用.
List<string> lists = new List<string>();
//Code to retrieve lists from DB
foreach (string list in lists)
{
Button btn = new Button();
btn.Click += new EventHandler(delegate { MessageBox.Show(list); });
}
Run Code Online (Sandbox Code Playgroud)
我每次启动时都只运行一次.现在似乎工作正常.正如Jon在某些情况下提到的反直觉结果一样.那么我需要注意什么呢?如果列表不止一次运行会没问题吗?
我有以下代码:
string acctStatus = account.AccountStatus.ToString();
if (!SettableStatuses().Any(status => status == acctStatus))
acctStatus = ACCOUNTSTATUS.Pending.ToString();
Run Code Online (Sandbox Code Playgroud)
请注意,account.AccountStatus是ACCOUNTSTATUS类型的枚举.在第二行,ReSharper向我发出了acctStatus的"访问修改后的关闭"的警告.当我执行建议的操作,复制到本地变量时,它将代码修改为以下内容:
string acctStatus = realAccount.AccountStatus.ToString();
string s = acctStatus;
if (!SettableStatuses().Any(status => status == s))
acctStatus = ACCOUNTSTATUS.Pending.ToString();
Run Code Online (Sandbox Code Playgroud)
为什么这比我原来的更好或更好?
编辑
它还建议在数组中包装局部变量,它产生:
string[] acctStatus = {realAccount.AccountStatus.ToString()};
if (!SettableStatuses().Any(status => status == acctStatus[0]))
acctStatus[0] = ACCOUNTSTATUS.Pending.ToString();
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎很奇怪.
我收到了这个ReSharper警告:在关闭时访问foreach变量.使用不同版本的编译器编译时可能会有不同的行为.
这就是我正在做的事情:
@foreach(var item in Model)
{
// Warning underlines "item".
<div>@Html.DisplayBooleanFor(modelItem => item.BooleanField)</div>
}
Run Code Online (Sandbox Code Playgroud)
我的扩展如下:
public static MvcHtmlString DisplayBooleanFor<TModel, TValue>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, TValue>> expression)
{
bool value;
try
{
var compiled = expression.Compile()(helper.ViewData.Model);
value = Convert.ToBoolean(compiled);
}
catch (Exception)
{
value = false;
}
return MvcHtmlString.Create(value ? "Yes" : "No");
}
Run Code Online (Sandbox Code Playgroud)
请注意这是按预期工作但我如何避免此警告?
我将不胜感激任何帮助.
鉴于:
void AFunction()
{
foreach(AClass i in AClassCollection)
{
listOfLambdaFunctions.AddLast( () => { PrintLine(i.name); } );
}
}
void Main()
{
AFunction();
foreach( var i in listOfLambdaFunctions)
i();
}
Run Code Online (Sandbox Code Playgroud)
现在你会认为这样做会对等:
void Main()
{
foreach(AClass i in AClassCollection)
PrintLine(i.name);
}
Run Code Online (Sandbox Code Playgroud)
但它没有,它将做的是每次打印AClassCollection中最后一项的名称!所以基本上每个lambda函数都使用相同的项目.我怀疑"当lambda被创建时"或"当它使用其中使用的外部变量的快照时"可能会有一些延迟,或者基本上只是持有'对局部变量的引用'i'
所以我这样做了:
string astr = "a string";
AFunc fnc = () => { System.Diagnostics.Debug.WriteLine(astr); };
astr = "changed";
fnc();
Run Code Online (Sandbox Code Playgroud)
而惊喜,惊喜,它输出"改变了!"
我正在使用XNA 3.1(无论是什么c#)
到底是怎么回事?lambda函数以某种方式存储变量或其他东西的"引用"吗?反正这个问题呢?
下面的代码输出33而不是012.我不明白为什么在每次迭代中没有捕获新变量loopScopedi而不是捕获相同的变量.
Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
{
actions [i] = () => {int loopScopedi = i; Console.Write (loopScopedi);};
}
foreach (Action a in actions) a(); // 333
Run Code Online (Sandbox Code Playgroud)
Hopwever,这段代码产生012.两者之间有什么区别?
Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
{
int loopScopedi = i;
actions [i] = () => Console.Write (loopScopedi);
}
foreach (Action a in actions) a(); // 012
Run Code Online (Sandbox Code Playgroud) 可能重复:
什么是'关闭'?
访问修改后的闭包
访问修改后的闭包(2)
Resharper抱怨下面这段代码:
foreach (string data in _dataList)
DoStuff (() => field);
Run Code Online (Sandbox Code Playgroud)
什么是关闭?我为什么要关心?
我已经读过关于数学和函数式编程的闭包,我在这里不知所措.我的大脑太沉重了.
简单来说,这里发生了什么?
我最近在阅读Rob Miles(这里)的非常好的pdf时进入了Threads .他在第160页(2012年,C#pdf)上有一个例子,但它没有写入控制台只是空循环.
我写了一个非常简单的线程生成循环,它创建了10个线程,在1000的每个倍数上将它们的ID写入屏幕.这很好 - 它向我展示了线程如何一起运行.我的问题从为什么我的输出如此困惑开始?通常当我运行下面的程序时,我会得到多个"Thread 3 Finished"行,我很确定,我应该只有一个.
我从MSDN 添加了一个"锁定"到循环但它似乎仍然产生奇数输出(我将在下面举一个例子).
namespace ConsoleApplication1
{
class Program
{
static object sync = new object();
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread myThread = new Thread(() => DoThis(i));
myThread.Start();
}
Console.ReadLine();
}
static void DoThis(int s)
{
lock (sync) // a new addition that hasn't helped
{
for (long j = 0; j < 10000; j++)
{
if (j % …Run Code Online (Sandbox Code Playgroud) public virtual void OnRegistrationJoin(RegistrationJoinEventArgs e)
{
foreach (Mobile member in e.Team)
{
member.SendMessage(1161, "You join the {0}.", EventFullName);
if (e.Team.Count > 1)
{
Joinees.Remove(member);
member.SendMessage(1161, "Your team formation is:");
int i = 0;
foreach (Mobile parter in e.Team.Where(partner => partner != member).ToList())
{
member.SendMessage(1150, "{0}: {1}.", ++i, partner.Name);
}
}
}
Members.Add(e.Team);
}
Run Code Online (Sandbox Code Playgroud)
我通过resharper获得"访问修改后的闭包"警告,我想知道这段代码有什么问题,因为我在内循环中所做的只是发送消息?
我有一个帮助方法,用于我的单元测试,断言特定顺序的事件是按特定顺序引发的.代码如下:
public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction)
{
var expectedSequence = new Queue<int>();
for (int i = 0; i < subscribeActions.Count; i++)
{
expectedSequence.Enqueue(i);
}
ExpectEventSequence(subscribeActions, triggerAction, expectedSequence);
}
public static void ExpectEventSequence(Queue<Action<EventHandler>> subscribeActions, Action triggerAction, Queue<int> expectedSequence)
{
var fired = new Queue<int>();
var actionsCount = subscribeActions.Count;
for(var i =0; i< actionsCount;i++)
{
subscription((o, e) =>
{
fired.Enqueue(i);
});
}
triggerAction();
var executionIndex = 0;
var inOrder = true;
foreach (var firedIndex in fired)
{
if (firedIndex != …Run Code Online (Sandbox Code Playgroud) c# ×9
resharper ×4
closures ×3
lambda ×3
.net ×1
events ×1
javascript ×1
scope ×1
unit-testing ×1
warnings ×1