2017-08-11 80 views
1

在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

回答

0

這個相當簡單的例子表明,從本質上講,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

1

由於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); 
    } 
}