作用域,C中的变量访问#
在Javascript中,内部函数可以访问外部函数的变量。因此在下面的示例中,可以在this.depthTraverse
函数中访问objFlag
。作用域,C中的变量访问#
Tree.prototype.findNodeWithValue = function(valueToFind){
var objFlag = {found: false, node: null}
this.depthTraverse(function(foundNode){
if(foundNode.data === valueToFind){
objFlag.found = true;
objFlag.node = foundNode;
}
})
return objFlag
}
我想以相同的方式写在C#中的等价物,但实现我遇到一些范围界定问题。 FWIW,我不熟悉使用委托,函数或动作,所以我可以肯定会丢失的东西,但对我来说,即使我可以在C#中传递一个方法,它也不会访问任何外部变量它被调用的函数?有没有办法编写与上面的代码等价的内容,但在C#中?而且我不要求相同的输出或结果,我要求以相同的方式传递函数并改变外部变量状态。下面
depthTraverse
实现以供参考:
Tree.prototype.depthTraverse = function(fn){
var queue = [];
queue.push(this.root);
while(queue.length > 0){
var nodeToInspect = queue.pop();
if(nodeToInspect.leaves.length !== 0){
queue.unshift(...nodeToInspect.leaves) // breadth first
}
if(fn){
fn(nodeToInspect);
}
}
}
------ UPDATE ------
我相信,我来到了基于@ JonWeeder的答案的解决方案。下面:
private static Node<T> holder {get;set;}
public Node<T> FindValue(T value){
Node<T> node;
TraverseDFS(value, (el) => {
if(Comparer<T>.Equals(el.Value, value)){
holder = el;
}
});
node = holder;
holder = null;
return node == null ? null : node;
}
private void TraverseDFS(T value, Action<Node<T>> action)
{
var queue = new List<Node<T>>();
queue.Add(this.Root);
while(queue.Count > 0){
var currentNode = queue[0];
queue.RemoveAt(0);
if(currentNode.Leaves.Count > 0){
queue.AddRange(currentNode.Leaves);
}
action(currentNode);
}
}
这是尽可能接近我的Javascript的实现。虽然未经测试,但IDE并不抱怨。
这个相当简单的例子表明,从本质上讲,C#可以与关于闭包的JS类似地工作。 动作指定传入的参数是一个不带参数且不返回任何内容的函数。 ()=> ...是一种定义简单lambda的方法 - 实质上是一种内联函数。
public class ObjFlag { public bool Found { get; set; } }
public void DoSomething(Action action)
{
action();
}
public void Sample()
{
var objFlag = new ObjFlag { Found = false };
DoSomething(() => objFlag.Found = true);
Assert.IsTrue(objFlag.Found);
}
也许有必要展示lambda语法的多行变体以及改进此答案? –
谢谢,我想我从你的例子中得到了一个解决方案。 – mche
由于C#是一个statically typed language,我写了作为一个例子的代码看起来有点不同,从你的榜样,但我希望它或多或少同样的事情。请同时参阅行动<>和Func <>代理类型文档或此wonderful blog post。
class Node
{
public int Data { get; set; }
// omitting other Node details here
}
class ObjFlag
{
public Node Node { get; set; }
public bool Found { get; set; }
}
class Tree
{
public ObjFlag FindNodeWithValue(int valueToFind)
{
var objFlag = new ObjFlag() { Found = false, Node = null };
DepthTraverse(node =>
{
if (node.Data == valueToFind)
{
objFlag.Node = node;
objFlag.Found = true;
}
});
return objFlag;
}
public void DepthTraverse(Action<Node> action)
{
Node nodeToInspect = null;
// some logic to get the node to inspect
if (action != null)
action(nodeToInspect);
}
}
https://asizikov.github.io/2016/04/15/thoughts-on-local-functions/ – zzxyz
@zzxyz这个例子是一个匿名方法,而不是本地方法。 – Servy
@Servy我认为本文在解决范围问题方面做得很好,并提供了在C#7之前工作的解决方案。我也不确定您指的是什么样的示例。如果你指的是链接,肯定有几个例子不是匿名的。不过,我可能会误解你的观点。 – zzxyz