【问题标题】:Scoping, variable access in C#C# 中的作用域、变量访问
【发布时间】:2018-01-20 11:08:48
【问题描述】:

在 Javascript 中,内部函数可以访问外部函数的变量。所以在下面的例子中,objFlag 可以在 this.depthTraverse 函数中访问。

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

----- 更新 ------

我相信我根据@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 并没有抱怨。

【问题讨论】:

  • @zzxyz 这个例子是匿名方法,不是本地方法。
  • @Servy 我认为这篇文章很好地解决了范围界定问题,并提供了适用于 C# 7 之前的解决方案。我也不确定您指的是哪个示例。如果您指的是链接,那么肯定有几个不是匿名的例子。不过,我可能误解了你的意思。

标签: javascript c# scope callback delegates


【解决方案1】:

由于 C# 是 statically typed language,我作为示例编写的代码看起来与您的示例有点不同,但我希望它或多或少地做同样的事情。另请查看 Action 和 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);
    }
}

【讨论】:

    【解决方案2】:

    这个相当简单的例子表明,从本质上讲,C# 在闭包方面可以与 JS 类似地工作。 Action 指定传入的参数是一个不接受任何参数并且不返回任何内容的函数。 () =>... 是一种定义简单 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 语法的多行变体以改进此答案是否有意义?
    • 谢谢,我想我从你的例子中得到了解决方案。
    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多