C#_delegate - Pair<T> 静态绑定

本文介绍了一个使用 C# 实现的简单泛型集合类 Pair 的例子,该类利用委托来决定两个元素的先后顺序,并展示了如何通过 Dog 和 Student 类型的具体实例来运用这些功能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Starter
{
    public enum Comparison
    {
        theFirstComesFirst = 1,
        theSecondComesFirst = 2
    }

    //包含两项的简单集合
    public class Pair<T>
    {
        //存放两个对象的私有数组
        private T[] thePair = new T[2];
        //委托声明
        public delegate Comparison WhichIsFirst(T obj1, T obj2);
        //构造方法,参数为两个对象,按接收顺序添加
        public Pair(T firstObject, T secondObject)
        {
            thePair[0] = firstObject;
            thePair[1] = secondObject;
        }

        //公共方法,按对象具体顺序范畴排序 - 被绑定的函数的返回值作为函数的参数
        public void Sort(WhichIsFirst theDelegatedFunc)
        {
            if (theDelegatedFunc(thePair[0], thePair[1]) == Comparison.theSecondComesFirst)
            {
                T temp = thePair[0];
                thePair[0] = thePair[1];
                thePair[1] = temp;
            }
        }

        //反序排列
        public void ReverSort(WhichIsFirst theDelegatedFunc)
        {
            if (theDelegatedFunc(thePair[0], thePair[1]) == Comparison.theFirstComesFirst)
            {
                T temp = thePair[0];
                thePair[0] = thePair[1];
                thePair[1] = temp;
            }
        }

        //要求两个对象提供字符串值
        public override string ToString()
        {
            return thePair[0].ToString() + ", " + thePair[1].ToString();
        }
    }

    public class Dog
    {
        //静态绑定
        public static readonly Pair<Dog>.WhichIsFirst OderDog = new Pair<Dog>.WhichIsFirst(WhichDogComesFirst);

        private int weight;

        public Dog(int weight)
        {
            this.weight = weight;
        }

        public static Comparison WhichDogComesFirst(Dog d1,Dog d2)
        {
            return d1.weight > d2.weight ?
                Comparison.theSecondComesFirst : Comparison.theFirstComesFirst;
        }

        public override string ToString()
        {
            return weight.ToString();
        }
    }

    public class Student
    {
        //类中进行静态绑定
        public static readonly Pair<Student>.WhichIsFirst OrderStudents =
            new Pair<Student>.WhichIsFirst(Student.WhichStudentComesFirst);

        private string name;

        public Student(string name)
        {
            this.name = name;
        }

        public static Comparison WhichStudentComesFirst(Student s1, Student s2)
        {
            return (String.Compare(s1.name, s2.name)<0 ?
                Comparison.theFirstComesFirst : Comparison.theSecondComesFirst
                );
                
        }

        public override string ToString()
        {
            return name;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Student Jess = new Student("Jess");
            Student Mary = new Student("Mary");
            Dog Milo = new Dog(26);
            Dog Free = new Dog(12);

            Pair<Student> studentPair = new Pair<Student>(Mary,Jess);
            Pair<Dog> dogPair = new Pair<Dog>(Milo, Free);

            studentPair.Sort(Student.OrderStudents) ;
            Console.WriteLine(studentPair.ToString());

            Console.ReadLine();
        }
    }

}

<think>好的,我现在需要帮助用户理解一段Unity中的代码。用户给出的代码是: _sceneDropdown.GetComponent<Dropdown>().onValueChanged.AddListener(delegate { LoadScene(_sceneDropdown.GetComponent<Dropdown>().value); }); 首先,我需要确定用户的主要问题是什么。看起来他们可能想了解这段代码的作用,或者在使用过程中遇到了问题,比如事件不触发、空引用异常等。不过根据用户的问题描述,他们可能只是需要这个代码的详细解释。 接下来,我需要拆解这段代码的每个部分。首先,_sceneDropdown可能是一个UI Dropdown组件的引用。通过GetComponent<Dropdown>()获取该组件,然后订阅onValueChanged事件。当Dropdown的值改变时,触发匿名委托(delegate),调用LoadScene方法,并传递当前Dropdown的value值。 用户可能对Unity的事件系统不太熟悉,特别是AddListener和匿名委托的使用。另外,可能需要解释为什么使用GetComponent多次,是否有性能问题,或者是否有更好的方法,比如缓存Dropdown组件。 还要考虑用户可能的错误,比如_sceneDropdown未正确赋值,导致空引用;或者LoadScene方法没有正确实现参数。此外,Unity的UI组件生命周期和事件绑定时机也是需要注意的地方,比如是否在Awake或Start中正确初始化。 需要分步骤解释代码结构,说明每个方法的作用,比如GetComponent、AddListener、匿名函数,以及事件参数的处理。同时,对比使用匿名委托和单独定义方法的区别,比如代码简洁性和可维护性。 另外,可能提到Unity的UI事件系统,Dropdown组件的onValueChanged是UnityEvent<int>,因此需要传递一个接受int参数的函数。这里使用delegate来包裹方法调用,确保参数正确传递。 最后,给出优化建议,比如缓存Dropdown组件,避免每次访问都调用GetComponent,提升性能。还可以提供示例代码,展示如何正确初始化和使用,以及如何处理可能出现的异常情况,比如添加错误检查或日志输出。 总结,回答的结构需要包括代码作用、分解解释、注意事项、优化建议、应用场景和常见问题,确保用户能够全面理解这段代码的工作原理和最佳实践。</think>--- ### **代码功能概述** 这段代码用于 **监听Unity UI Dropdown组件的选项变化事件**,当用户选择不同选项时,触发加载对应场景的逻辑。以下是逐层解析: --- ### **1. 代码结构分解** ```csharp _sceneDropdown.GetComponent<Dropdown>().onValueChanged.AddListener(delegate { LoadScene(_sceneDropdown.GetComponent<Dropdown>().value); }); ``` - **`_sceneDropdown`**: 一个 `GameObject` 或 `Transform` 的引用,需提前在Inspector面板关联到UI Dropdown组件。 - **`GetComponent<Dropdown>()`**: 获取该对象上的 `Dropdown` 组件(Unity的UI下拉菜单组件)。 - **`onValueChanged`**: Dropdown的事件,当用户选择新选项时触发。 - **`AddListener()`**: 订阅事件的方法,参数为事件触发时调用的函数。 - **`delegate { ... }`**: 匿名委托(无名称的临时函数),直接定义事件触发时的行为。 - **`LoadScene(value)`**: 自定义方法,根据Dropdown的当前选项值加载场景。 --- ### **2. 关键点详解** #### **(1) 事件订阅机制** - **核心逻辑**: 将 `onValueChanged` 事件与 `LoadScene` 方法绑定- **触发条件**: 当用户点击Dropdown并选择新选项时,Unity会传递当前选项的索引值(`int` 类型)。 #### **(2) 匿名委托 vs 显式方法** - **匿名委托**: ```csharp // 直接内联定义逻辑 AddListener(delegate { /* 代码 */ }); ``` - **优点**: 代码紧凑,适合简单操作。 - **缺点**: 难以复用,可能导致重复代码。 - **显式方法**: ```csharp // 先定义方法 void OnDropdownValueChanged(int index) { LoadScene(index); } // 再绑定事件 dropdown.onValueChanged.AddListener(OnDropdownValueChanged); ``` - **优点**: 逻辑分离,易于维护。 - **缺点**: 需额外编写方法。 --- ### **3. 完整代码示例** ```csharp using UnityEngine; using UnityEngine.UI; public class SceneLoader : MonoBehaviour { public GameObject _sceneDropdown; // Inspector面板关联Dropdown对象 void Start() { // 获取Dropdown组件并绑定事件 Dropdown dropdown = _sceneDropdown.GetComponent<Dropdown>(); dropdown.onValueChanged.AddListener(delegate { LoadScene(dropdown.value); }); } void LoadScene(int sceneIndex) { // 根据索引加载场景(需提前在Build Settings中添加场景) UnityEngine.SceneManagement.SceneManager.LoadScene(sceneIndex); } } ``` --- ### **4. 注意事项** 1. **组件引用安全**: - 确保 `_sceneDropdown` 在Inspector面板正确关联,否则 `GetComponent<Dropdown>()` 会返回 `null`,导致运行时错误。 - 可添加空引用检查: ```csharp if (_sceneDropdown != null && _sceneDropdown.GetComponent<Dropdown>() != null) { // 绑定事件 } ``` 2. **性能优化**: - 避免重复调用 `GetComponent<Dropdown>()`,可在 `Start` 或 `Awake` 中缓存组件: ```csharp private Dropdown _dropdown; void Start() { _dropdown = _sceneDropdown.GetComponent<Dropdown>(); _dropdown.onValueChanged.AddListener(...); } ``` 3. **场景索引配置**: - Dropdown的 `value` 对应场景在 **Build Settings** 中的索引(需提前添加场景)。 - 示例:若Dropdown选项0对应场景索引2,需确保Build Settings中索引2的场景存在。 --- ### **5. 扩展应用** #### **(1) 动态填充Dropdown选项** ```csharp // 根据场景名称列表初始化Dropdown void InitDropdown() { _dropdown.ClearOptions(); List<string> sceneNames = new List<string> { "主菜单", "关卡1", "关卡2" }; _dropdown.AddOptions(sceneNames); } ``` #### **(2) 多语言支持** ```csharp // 根据语言切换选项文本 _dropdown.options[0].text = LocalizationManager.GetText("MainMenu"); ``` --- ### **6. 常见问题排查** | 问题现象 | 可能原因 | 解决方案 | |-------------------------|-------------------------------|------------------------------| | 事件未触发 | Dropdown组件未正确绑定 | 检查Inspector面板关联 | | 场景加载错误 | Build Settings未添加对应场景 | 在File > Build Settings中添加场景 | | 空引用异常 | 未缓存Dropdown组件 | 使用缓存避免重复调用GetComponent | --- ### **7. 替代方案对比** | 实现方式 | 适用场景 | 缺点 | |------------------------|-------------------------------|-------------------------------| | 匿名委托 | 简单逻辑,快速开发 | 代码可读性差,难以维护 | | UnityEvent Inspector绑定 | 非代码人员协作 | 依赖手动拖拽,灵活性低 | | 显式方法 | 复杂逻辑,代码复用 | 需额外编写方法 | --- 通过合理使用事件绑定,可以实现灵活的UI交互逻辑。此代码常见于场景切换、配置选择等场景,是Unity UI开发的基础技能之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值