作用域,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并不抱怨。

+0

https://asizikov.github.io/2016/04/15/thoughts-on-local-functions/ – zzxyz

+0

@zzxyz这个例子是一个匿名方法,而不是本地方法。 – Servy

+0

@Servy我认为本文在解决范围问题方面做得很好,并提供了在C#7之前工作的解决方案。我也不确定您指的是什么样的示例。如果你指的是链接,肯定有几个例子不是匿名的。不过,我可能会误解你的观点。 – zzxyz

这个相当简单的例子表明,从本质上讲,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); 
    } 
+0

也许有必要展示lambda语法的多行变体以及改进此答案? –

+0

谢谢,我想我从你的例子中得到了一个解决方案。 – 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); 
    } 
}