C# 防止委托回调中处于已删除状态的对象

C# 防止委托回调中处于已删除状态的对象,c#,events,unity3d,delegates,C#,Events,Unity3d,Delegates,我正在用Unity3D编写一个游戏,我想知道我是否应该在web请求中使用事件(或者完全使用其他构造)而不是委托 在游戏生命周期的某些时刻,我们需要调用RESTAPI并等待它的响应。考虑一个UI屏幕,它可以检索你朋友的列表,并显示朋友的数量,以及每个朋友的条目。当前,工作流类似于这样,使用操作委托作为my服务器类的各种方法的参数: class FriendsUI : MonoBehaviour { [SerializeField] private Text friendCount;

我正在用Unity3D编写一个游戏,我想知道我是否应该在web请求中使用事件(或者完全使用其他构造)而不是委托

在游戏生命周期的某些时刻,我们需要调用RESTAPI并等待它的响应。考虑一个UI屏幕,它可以检索你朋友的列表,并显示朋友的数量,以及每个朋友的条目。当前,工作流类似于这样,使用
操作
委托作为my
服务器
类的各种方法的参数:

class FriendsUI : MonoBehaviour
{
    [SerializeField]
    private Text friendCount; // A Unity Text component

    private void OnStart()
    {
        Server.GetFriends(player, response => {
            ShowFriendList(response.friends);
        });
    }

    private void ShowFriendList(List<Friend> friends)
    {
        this.friendCount.text = friends.Count.ToString();
        // Display friend entries...
    }
}
class-FriendsUI:单一行为
{
[序列化字段]
私有文本friendCount;//统一文本组件
私有void OnStart()
{
Server.GetFriends(播放器,响应=>{
ShowFriendList(response.friends);
});
}
私人void ShowFriendList(列出好友)
{
this.friendCount.text=friends.Count.ToString();
//显示好友条目。。。
}
}
Server.GetFriends
方法向RESTAPI发出HTTP请求,获取响应并调用委托,将响应和控制返回给
FriendsUI

这通常效果很好。但是,如果我在调用委托之前关闭了friends UI屏幕,那么
friendCount
组件以及类中的任何其他组件都已被销毁,并且试图访问它时抛出了一个NPE

知道了这一点,你认为C#的事件系统是更好的设计吗
Server
将公开类似于
FriendsEvent
事件的内容,而
FriendsUI
将订阅它。当
Server
验证/转换响应时,它将引发事件
FriendsUI
也会在脚本附加的游戏对象被销毁/禁用后进行清理并注销处理程序。这样,在
Server
中引发事件时,如果事件处理程序在
FriendsUI
中不再有效,它就不会被调用

我只是想在实现它之前在脑子里把它想清楚,因为它最终会变成一个有点大的重构。我正在寻找指导,看看人们是否认为这是一条好的路线,是否还有其他的路线可能会变得更好,以及我在途中可能遇到的任何陷阱

一如既往地感谢您的时间。

只需使用C#
委托
事件
。使每个脚本在从服务器收到好友列表时收到通知,以订阅活动

public class FRIENDSAPI : MonoBehaviour
{
    public delegate void friendListReceived(List<FRINDSINFO> _friends);
    public static event friendListReceived onFriendListReceived;

    //Function that gets friends from the network and notify subscribed functions with results
    public void getFriends()
    {
      StartCoroutine(getFriendsCoroutine());
    }

    private IEnumerator getFriendsCoroutine()
    {
     List<FRINDSINFO> friendsFromNetwork = new List<FRINDSINFO>();

     /*
     NETWORK CODE

     //FILL friendsFromNetwork with Result
     friendsFromNetwork.Add();

     */


     //Make sure a function is subscribed then Notify every subscribed function
      if (onFriendListReceived != null)
      {
        onFriendListReceived(friendsFromNetwork);
      }

     yield return null;
     }
}

谢谢你的评论。如果我最终使用事件,看起来这就是我要走的路线。然而,我想让人们运行的主要事情是,事件是否是他们认为最适合这种类型场景的方法,或者是否有一种通过代理实现的方法(即修改我当前的路线)或者如果有其他更适合我的方法。@Monkey34您可以使用
操作
或按自己的方式操作,但重要的是确保每次销毁/禁用订阅的类时都取消订阅。否则会带来另一个问题。学会使用UnityEvent。再容易不过了。谢谢你的信息,乔。UnityEvent系统似乎有点过于冗长,但这可能是最好的选择。例如,按照我的想法,我需要在我的
服务器
类中公开一个
FriendsResponseEvent
类,该类扩展了
UnityEvent
。我还需要在
Server
中声明并实例化一个
FriendsResponseEvent
属性。然后我将
Server.FriendsResponseEvent.AddListener(ReceivedFriends)
添加到我的
FriendsUI\OnStart
方法中。这种模式需要发生在服务器想要引发的每一个事件中,这变得非常冗长。或者可能有一种更简洁的方法?作为测试,可以这样做:(1)type
public UnityEvent teste在您的服务器类中。(2) 在该类中的某个地方(例如,连接完成后)转到
teste.Invoke()
。最后(3)查看服务器类的检查器。现在拖动你想“测试”的任何东西(以这种方式连接任意多个)。永远不要使用“AddListener”,因为没有必要使用它。我不同意使用
AddListener
。在我看来,当开发人员希望通过代码连接监听器时,绝对需要它。这样做比通过检查员把他们联系起来要舒服得多。我很乐意让游戏设计师通过inspector连接某些事件,但是这个用例是开发人员需要管理的,代码是我们做这件事的首选渠道。如果这是一个单一开发人员的操作,那么检查器可能还可以,但这里的情况并非如此。无论哪种方式,我都会继续将
UnityEvent
作为解决方案。
public class FriendsUI: MonoBehaviour
{

    void Start()
    {
        //Subscribe
        FRIENDSAPI.onFriendListReceived += onFriendsReceived;

        FRIENDSAPI friendAPI = gameObject.GetComponent<FRIENDSAPI>();
        friendAPI.getFriends(); //Get friends
    }

    public void OnDisable()
    {
        //Un-Subscribe
        FRIENDSAPI.onFriendListReceived -= onFriendsReceived;
    }

    //Call back function when friends are received
    void onFriendsReceived(List<FRINDSINFO> _friends)
    {
        //Do Whatever you want with the result here(Display on the Screen)
    }
}