列表在继承中为空(C#,Unity)

列表在继承中为空(C#,Unity),c#,unity3d,inheritance,C#,Unity3d,Inheritance,我很抱歉,如果这是一个有点基本的,但我不能找出问题 我有三门课: public class ClassA : MonoBehavior { public List<T> list; void Start() { list = new List<T>; //then fill the list. } } public class ClassB : ClassA { vo

我很抱歉,如果这是一个有点基本的,但我不能找出问题

我有三门课:

public class ClassA : MonoBehavior
{
     public List<T> list;  
     
     void Start()
       {
        list = new List<T>; 
        //then fill the list. 
       }
}

public class ClassB : ClassA
{
  void DoesSomething()
  {
     if(list.Count != 0)
  }
} 

public interface IClassB { ClassB classB { get; set;} }; 
public class ClassC: MonoBehaviour, IClassB
{
   public ClassB classB { get; set;}
    
   void Start()
   {
     classB = new ClassB();
   }
    
   public void OnButtonClick()
   {
      classB.DoesSomething();
   }
}
公共类ClassA:单行为
{
公开名单;
void Start()
{
列表=新列表;
//然后填写清单。
}
}
B类:A类
{
void doesmething()
{
如果(list.Count!=0)
}
} 
公共接口IClassB{ClassB ClassB{get;set;};
公共类C类:单一行为,IClassB
{
公共类B类B{get;set;}
void Start()
{
classB=新的classB();
}
public void on按钮单击()
{
classB.DoesMething();
}
}
现在,当我在ClassC中调用doesMething()函数时,我在检查ClassB中列表计数的行中得到一个null异常,即使我在ClassA的start函数中初始化并填充了列表。我对它进行了调试,以检查它是否正确初始化

因此,我可能遗漏了一些关于接口、统一性和C#继承的东西。
我感谢您的帮助和提前感谢

你的
ClassB
是一种
单一行为

您永远不会使用
new
关键字实例化
单一行为(或通常派生的任何行为)
!从来没有

撇开幽默不谈,Unity实际上应该对此提出警告。这毫无意义。每个
monobhavior
都属于
GameObject
的特定实例。因此,创建实例的有效方法只有三种:

  • 使用的构造函数创建一个新的空
    游戏对象
    ,并附加相应的组件
  • 在现有的
    游戏对象上使用
    为此,请将该组件添加到
    游戏对象
  • 用于克隆现有的
    游戏对象
    ,或实例化连接了相应组件的预制实例
由于通过
new
创建实例是高度“非法”的,因此不会调用任何
Start
方法


因此,既然你的类应该而不是附加到某个
游戏对象
,但是你要通过
new
创建一个实例,移除
单一行为
继承,而是使用一个合适的类

public class ClassA
{
    // And then why not simply initialize the list by default?
    // that avoids these kind of initialization problems already right from the beginning
    public List<T> list = new List<T>(); 
     
    // And do the rest of your initialization stuff in a proper constructor
    public ClassA()
    { 
        //then fill the list. 
    }
}

public class ClassB : ClassA
{
    public void DoesSomething()
    {
         if(list.Count != 0) { }
    }
} 
 

但是,如果你的
ClassA
(从而
ClassB
实际上应该是一种
单一行为
,那么你不想使用
新的
,而是以不同的方式获得一个实例。参见前面

但是,由于
Start
被称为消息,因此它仅在最后一个实现中被调用,因此仅适用于
ClassB

因此,对于嵌套继承的
monobhavior
,建议将UnityMessage方法(如
Awake
Start
等)设置为
虚拟的
,并在派生类(如

public class ClassA : MonoBehaviour
{
    // And then why not simply initialize the list by default?
    // that avoids these kind of initialization problems already right from the beginning
    public List<T> list = new List<T>(); 
     
    protected virtual void Start()
    { 
        //then fill the list. 
    }
}

public class ClassB : ClassA
{
    protected override void Start()
    {
        base.Start();

        // Additional stuff specific for this type
    }

    public void DoesSomething()
    {
         if(list.Count != 0) { }
    }
} 
公共类ClassA:单一行为
{
//那么,为什么不在默认情况下简单地初始化列表呢?
//这从一开始就避免了此类初始化问题
公共列表=新列表();
受保护的虚拟void Start()
{ 
//然后填写清单。
}
}
B类:A类
{
受保护的覆盖无效开始()
{
base.Start();
//特定于此类型的其他内容
}
公共无效DoesMething()
{
如果(list.Count!=0){}
}
} 

ClassA.Start()
私有的
,所以我看不出您最终会在哪里调用它。@dbc是由Unity框架本身作为消息调用的。在这种情况下,尽管OP使用
new
创建实例,这对于从
组件
派生的任何类型来说都是绝对“非法的”)下面是我的答案谢谢你的答案@derHugo!我已将列表更改为在声明时初始化。这有助于空引用,但并没有完全解决我的问题。我希望ClassA是一个单一行为,ClassC也是。它们都连接到游戏对象。B类不一定要附加到游戏对象上,这就是我为什么要这样做的原因。现在的问题是,ClassB有一个空列表,尽管我在ClassA的开头就填了它。所以我的问题是:关于继承,我遗漏了什么?@Temeos已经说过:您不能使用
new
创建新实例。如果您的
ClassA
monobhavior
,那么
ClassB
也是如此,因为它继承自
ClassA
。。。所以现在还不清楚你到底在做什么…我有一个ClassA脚本,我把它附加到一个游戏对象上。这个脚本包含一些可以在编辑器中修改的信息,以及所有这些东西。我有一个ClassB,它有一些方法,例如将ClassA中的内容保存为xml格式。ClassC有一组OnGui()方法来构建调用ClassB中方法的简单UI。我之所以这样做,是因为我认为让所有连接都基于继承会更好,而不是将所有脚本都附加到GO并一直使用FindObjectOfType。现在,我知道我可以用另一种方式,但是在这一点上,我的好奇心战胜了我,我想知道如何用我正在尝试的方式来做。我明白,问题是我使用了“new”关键字,但是如果不是FindObjectOfType(),还有什么选择呢?
public class ClassA : MonoBehaviour
{
    // And then why not simply initialize the list by default?
    // that avoids these kind of initialization problems already right from the beginning
    public List<T> list = new List<T>(); 
     
    protected virtual void Start()
    { 
        //then fill the list. 
    }
}

public class ClassB : ClassA
{
    protected override void Start()
    {
        base.Start();

        // Additional stuff specific for this type
    }

    public void DoesSomething()
    {
         if(list.Count != 0) { }
    }
}