闭包

闭包

闭包(Closure)是一个重要的编程概念,尤其在使用 C# 时。闭包是指一个函数可以捕获和记住它的作用域(上下文)中的变量,即使这个函数已经在其原始作用域之外被调用

闭包的基本概念

在 C# 中,匿名方法和 Lambda 表达式通常会创建闭包。闭包允许方法捕获局部变量并在稍后某个时刻使用这些变量。

示例:

  • 闭包:此时第一个for循环中Log的i将产生闭包“captured variable is modified in the outer scope”,即“捕获的变量在外部范围中被修改”。后续输出都是最后一个i值,因为闭包捕获的是变量 i 的引用,而不是当前值。

image-20250111205342902

  • 避免闭包:通过创建局部变量 temp,确保闭包捕获的是变量的值而不是引用。

image-20250111205151475

Unity开发中常见的闭包场景

1.延迟任务(例如协程)

闭包可以用于在延迟执行中捕获当前上下文变量,

    void Start()
    {
        for (int i = 5; i < 10; i++)
        {
            StartCoroutine(DelayedLog(x => i, i * 0.5f));//i被匿名方法捕获,延迟调用后i始终为10
        }
    }

    System.Collections.IEnumerator DelayedLog(Func<int,int> func, float delay)
    {
        yield return new WaitForSeconds(delay);
        Debug.Log($"Delayed index: {func.Invoke(0)}");//prints: Delayed index: 10
    }

2. 动态事件绑定

Unity 中的按钮事件或自定义事件监听器经常会用到闭包。

示例代码

csharp复制代码using UnityEngine;
using UnityEngine.UI;

public class ButtonClosureExample : MonoBehaviour
{
    public Button buttonPrefab;
    public Transform buttonParent;

    void Start()
    {
        for (int i = 0; i < 5; i++)
        {
            Button newButton = Instantiate(buttonPrefab, buttonParent);
            newButton.GetComponentInChildren<Text>().text = $"Button {index}";
            newButton.onClick.AddListener(() => Debug.Log($"Button {i} clicked"));
        }
    }
}

在这个例子中,会生成5个Button0~4的按钮,但是点击时输出的始终为Button 5 clicked

3. 异步任务(例如 UnityWebRequest 或异步加载)

在异步操作中,闭包可以帮助将参数传递给回调。

示例代码

csharp复制代码using UnityEngine;
using UnityEngine.Networking;

public class AsyncClosureExample : MonoBehaviour
{
    void Start()
    {
        string[] urls = { "https://example.com/file1", "https://example.com/file2" };
        foreach (string url in urls)
        {
            StartCoroutine(DownloadData(url));
        }
    }

    System.Collections.IEnumerator DownloadData(string url)
    {
        UnityWebRequest request = UnityWebRequest.Get(url);
        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            Debug.Log($"Downloaded from {url}: {request.downloadHandler.text}");
        }
        else
        {
            Debug.LogError($"Failed to download from {url}: {request.error}");
        }
    }
}

这里的 url 是通过闭包捕获的,每个协程实例会记住自己的 URL,即使下载任务是异步的。

总结

在 Unity 开发中,闭包是一种强大的工具,尤其在事件、协程、异步任务中非常有用。然而,使用闭包时需要小心捕获变量的行为,避免产生难以调试的错误。

posted @   世纪末の魔术师  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
  1. 1 ありがとう··· KOKIA
ありがとう··· - KOKIA
00:00 / 00:00
An audio error has occurred.

作词 : KOKIA

作曲 : KOKIA

编曲 : 日向敏文

作词 : KOKIA

作曲 : KOKIA

誰もが気付かぬうちに

誰もが気付かぬうちに

何かを失っている

フッと気付けばあなたはいない

思い出だけを残して

せわしい時の中

言葉を失った人形達のように

街角に溢れたノラネコのように

声にならない叫びが聞こえてくる

もしも もう一度あなたに会えるなら

もしも もう一度あなたに会えるなら

たった一言伝えたい

ありがとう

ありがとう

時には傷つけあっても

時には傷つけあっても

あなたを感じていたい

思い出はせめてもの慰め

いつまでもあなたはここにいる

もしも もう一度あなたに会えるなら

もしも もう一度あなたに会えるなら

たった一言伝えたい

ありがとう

ありがとう

もしも もう一度あなたに会えるなら

もしも もう一度あなたに会えるなら

たった一言伝えたい

もしも もう一度あなたに会えるなら

たった一言伝えたい

ありがとう

ありがとう

時には傷つけあっても

時には傷つけあっても

あなたを感じてたい

点击右上角即可分享
微信分享提示