Why C# downcast become null?

So here is my code,

public void CheckStatChal()    
{
   foreach (SpotUIBase menu in thisSpot.ownMenus)
   {
       if (menu.uiSort == SpotUISort.StatEvent)
       {
           if(menu != null)
               Debug.Log("Menu name is "+menu.Name);
           var statEvent = menu as StatEvent;
           if (statEvent == null)
           {
               Debug.Log("Stat event is null, name is "+thisSpot.Name);
               continue;
           }
           .......... [1]

public SpecialSpotClass thisSpot;
public abstract class SpecialSpotClass
{
public List<SpotUIBase> ownMenus = new List<SpotUIBase>();
....
public  class SpotUIBase
{
  public SpotUISort uiSort;
   ....
public class StatEvent : SpotUIBase
{
   ....
public enum SpotUISort{
   Inn, Shop, Bar,

I am using Unity engine now. So if run this code, I got Debug.Log("Menu name is "+menu.Name); and Debug.Log("Stat event is null, name is "+thisSpot.Name); both. Why? menu is not null, but after downcast it, it become null? I don’t understand this why.

So in this code, I want to execute [1] part below codes, but [statEvent] is null, so all the code below does not called by (continue keyword)

Why downcast become null?

Help please.

You’re using a safe cast (as), which returns null if it fails. This means that your menu object is not a StatEvent.

If you think the cast should always work, use a normal cast. Then you’ll get an exception from the cast, which is where you did something wrong, rather than a nullref on some arbitrary line further down.

It’s null because the cast fails. You’re trying to cast a base class into a derived class.

While a StatEvent is always a SpotUIBase, a SpotUIBase isn’t always a StatEvent.

The, how should it be? Eventually I want to access StatEvent’s own function.

Make the method public and any inherited class will be able to use it. That’s how inheritance works…

StatEvent’s method is already public, StatEvent’s null is problem.

If menu truly is a StatEvent then you can just call menu.Method(). There’s no need to cast. But given the fact that your safe cast is coming back null my guess is that menu isn’t a StatEvent in which case assuming that every menu is a StatEvent doesn’t seem to be a good assumption given your architecture.

Edit - now I sort of see what you’re doing. It’s not a downcast, it’s an upcast. So yeah, not every menu (SpotUIBase) is a StatEvent.

Just curious, but what reason are you making a list of SpotUIBase instead of a list of StatEvent? Are you trying to create a list that holds a bunch of different things that inherit from SpotUIBase?

So I googled and confirmed right Downcast method, and changed foreach to for syntax. And solved.

Here is changed code.

 public StatChal chal1;
for (int i = 0; i < thisSpot.ownMenus.Count; i++)
   {
       if (thisSpot.ownMenus[i].uiSort == SpotUISort.StatEvent)
       {
           thisSpot.ownMenus[i] = SpotUI.Instance.StatEvent;
           var ownMenu = (StatEvent) thisSpot.ownMenus[i];
           Debug.Log("own menu is "+ownMenu.Name);
           if ((!ownMenu.StatChal1.nowCoolTime && ownMenu.StatChal1 != null)
                                            || ownMenu.StatChal1 == null)
           {
               StatChallenge.Instance.MakeStatChal(this, ref ownMenu.StatChal1);
               Debug.Log(ownMenu.StatChal1.Name);
               ownMenu.SetChalInfo(ownMenu.StatChal1, 1);
               chal1 = ownMenu.StatChal1;
           }

So its started from game design, my game has various special in-game spots like Village, Dungeon, Ruins, etc.

And all of them will has its own specific menus. (ex. Village will has Inn, Shop, StatEvent UI menus)

So I made SpotUIBase class first and from there all specific ui menus (Inn, Shop,) inherited from it.

And at this thread, I want to make checking method that if some special spot has [StatEvent] UI menu, I want to pull specific [StatEvent] data from [StatEvent] manager class. (in my case, StatChallenge.cs)

Tested, but this does not worked well.

thisSpot.ownMenus = SpotUI.Instance.StatEvent;

So this line is not truly downcast itself, but just change its data.

So I just abandoned this downcasting approach and just get reference of each specific spot’s own script and store data to there.