【问题标题】:Unity: Null while making new class instanceUnity:创建新类实例时为空
【发布时间】:2019-03-13 11:19:23
【问题描述】:

我陷入了非常愚蠢的境地:我正在创建泛型类的新实例,但它返回“奇怪”的 null。

    Rule rule2 = new Rule(); // initiate the class
    Debug.Log(rule2); //1st debug
    rule2.RuleSetup(r: "CaughtEnough", li: 0); //setting up the parameters
    Debug.Log(rule2.rule); //2nd debug

第一次调试给了我

    null
    UnityEngine.Debug:Log(Object)

同时设置参数工作,第二次调试给我

   CaughtEnough
   UnityEngine.Debug:Log(Object)

这应该是正确的类实例中的内容。

它给我带来的一个(仅到目前为止)问题是,如果我调用这个 Rule 类实例

   Invoke(rule, 0f);

它给了我 NullReferenceException 错误。但同时实际功能

   CaughtEnough();

工作正常,符合预期。

任何想法可能是问题的根源以及如何克服它?

UPD 还按照要求发布了 Rule 类的设置部分,尽管它很简单

public class Rule : MonoBehaviour {

public string rule;

public int leftInt;
public Dictionary<string, int> leftDict;
public float countdown;

public int outcome;

public CatchManager catchMan;
public Net net;

// Use this for initialization
void Start () {
    RuleSetup();   
}

public void RuleSetup(string r = "NoRule", int li = 0, Dictionary<string, int> ld = null,  float cd = float.PositiveInfinity) {
    rule = r;
    leftInt = li;
    leftDict = ld;
    countdown = cd;
}
.....

【问题讨论】:

  • 只需通过 if(rule2==null){Debug.Log("null")}else{Debug.Log("Not null")} 来检查 rule2 是否为空。还要发布您的 Rule 类,以便我们可以看到 RuleSetup 是什么。
  • 谢谢,我按照你的建议检查了,rule2 确实为空。

标签: c# unity3d null


【解决方案1】:
public class Rule : MonoBehaviour{}
Rule rule2 = new Rule();

如果您从 MonoBehaviour 继承,您不能使用 new 关键字创建新实例。

你应该得到这样的异常:

您正在尝试使用“new”关键字创建 MonoBehaviour。 这是不允许的。 MonoBehaviours 只能使用添加 添加组件()。或者,您的脚本可以继承自 ScriptableObject 或根本没有基类

如果你有public class Rule {},但你有public class Rule : MonoBehaviour {},你的代码就可以工作。

创建派生自 MonoBehaviour 的类的新实例:

示例类:

public class Rule : MonoBehaviour
{
    public Rule(int i)
    {

    }
}

如果您从MonoBehaviour 继承,您应该使用GameObject.AddComponent 或Instantiate 来创建它的新实例。

Rule rule2 = null;
void Start()
{
  rule2 = gameObject.AddComponent<Rule>();
}

或

public Rule rulePrefab;
Rule rule2;
void Start()
{
    rule2 = Instantiate(rulePrefab) as Rule;
}

如果Rule 脚本已存在并附加到游戏对象,则无需创建/添加/实例化该脚本的新实例。只需使用GetComponent 函数从它所附加的 GameObject 中获取脚本实例。

Rule rule2;
void Start()
{
    rule2 = GameObject.Find("NameObjectScriptIsAttachedTo").GetComponent<Rule>();
}

您会注意到,当您从MonoBehaviour 派生脚本时,您不能在构造函数中使用该参数。



创建不派生自 MonoBehaviour 的类的新实例:

示例类:(注意它不是从“MonoBehaviour”派生的

public class Rule
{
    public Rule(int i)
    {

    }
}

如果您不从MonoBehaviour 继承,您应该使用new 关键字来创建它的新实例。现在,您可以根据需要在构造函数中使用参数。

Rule rule2 = null;

void Start()
{
    rule2 = new Rule(3);
}

编辑:

在最新版本的 Unity 中,使用 new 关键字创建从 MonoBehaviour 继承的脚本的新实例可能不会给您错误,也可能不是 null 但所有回调函数都不会执行。其中包括Awake、Start、Update 函数等。因此,您仍然必须按照本答案顶部所述正确执行此操作。

【讨论】:

  • 不知道,谢谢。这在我看来是一个非常奇怪的约定。
  • @Alex New Unity 用户体验过,包括我在内。哦,确保在创建 CatchManager 和 Net 的实例时执行相同的操作,这些实例位于 Rule 脚本中
  • 再次感谢,其他一切实际上都是带有预制件的实体对象。不知道为什么我认为在 Rule 的情况下我可以只上课:)
【解决方案2】:

只是一个跟进,我最终是如何做到的以及为什么这样做:

  1. 我不再从 MonoBehaviour 继承 Rule 类以避免跟踪游戏对象的创建和删除,这似乎很痛苦。

  2. 由于泛型类中不存在Invoke 方法,我将其替换为反射,如here 所述

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 2014-12-06
    相关资源
    最近更新 更多