A simple concept in C# I'm not understanding....

So there’s a very simple concept in C# that I haven’t really gotten to wrapping my head around…

Say I create a list like this:

public class MyClassFirst {
  public List<string> listOfStrings = new List<string>();
}

I’m not understanding how I would reference the list from a second …ummm…‘non-value’ (like a pointer kind of) in a second class without creating any new list object in MySecondSecond here:

public class MyClassSecond : MonoBehaviour {
 declare listOfStringsReference without creating a new list here
 MyClassFirst myClassFirst;
 Start() {
   myClassFirst = new MyClassFirst(); //now we're creating a new MyClassFirst?
   listOfStringsReference = myClassFirst.listOfStrings;
 }
}

I’ve been trying to understand the ref keyword. Is that how you do it? So would it be like:

ref List<string> MyClassFirst.listOfStrings myClassFirstsListOfStrings

Or something…I don’t know…

There’s just something in me which feels like it wouldn’t be the best to just create new lists every frame for a script that’s going to be attached to like 1000 game objects in my game…It even feels wrong above to use the new keyword so many times…Is it really okay performance wise to just do that 10,000 times in a frame, even if myClassFirst has all these other empty lists that were being created in that frame? If game objects held these scripts using the new keyword, wouldn’t that mean hundreds of thousands of objects created with the new keyword just on a single frame?

Obviously there’s something very simple I’m not understanding here.

My most basic question is to clarify: How do I reference the list without creating a new one, so I can change it’s values without creating a new list object?

no, ‘ref’ is used for method cal

ls. It allows you to pass in a value by reference to that method. Essentially the variable that is referenced is updated.

int v = 5;
Foo(ref v);
Debug.Log(v); //prints 6

void Foo(ref int value)
{
     value += 1;
}

OK… so that’s what ref is. Now onto references in general.

In C# we don’t get pointers (well you can will unsafe code, but we’re not gonna go there right now). Instead types are either ‘reference type’ or ‘value type’.

Classes are reference types.

Structs are value types.

A class object is thusly referenced.

var a = new List<string>();
var b = a; //b and a reference the same List

b.Add("hello");
Debug.Log(a[0]); //prints 'hello

Where as a struct or primitive value type is not:

int i = 5;
int j = i;
//i and j are not the same int
j += 1;
Debug.Log(i);//prints 5

In your example where you have a member of ‘MyClassFirst’ and you want ‘MyClassSecond’ to reference the list from MyClassFirst… you’ll have to assign the list in MyClassSecond to that of MyClassFirst.

Note, this is all done with instances of each… so we have to instantiate them!

public class MyClassFirst {
    public List<string> listOfStrings = new List<string>();
}

public class MyClassSecond : MonoBehaviour {
    List<string> listOfStrings;
    MyClassFirst myClassFirst;
    Start() {
        myClassFirst = new MyClassFirst(); //yes, we create a MyClassFirst, since we need a reference to one
        //you could also get a reference to one if one already exists elsewhere.
        listOfStrings = myClassFirst.listOfStrings;
    }
}

So now your concerns…

Every frame? You’re not creating it every frame. You’re creating them on ‘Start’.

You will use the new statement for every new object you’ll need. How many lists do you need?

Again, you’re not doing it every frame. You did it once at ‘Start’.

Why do you think you’re doing it every frame?

It sounds like you’re asking about a static member. While a normal member is a part of each instance of a class - if you have 500 Enemy objects there’s 500 copies of the list - a static member is part of the class itself, and is shared by all instances.

public class MyClassFirst {
public static List<string> listOfStrings;
}

//anywhere else
if (MyClassFirst.listOfStrings == null) MyclassFirst.listOfStrings = new List<string>();
MyClassFirst.listOfStrings.Add(gameObject.name+" was here.");

Static members are one of those things that should be used with caution, because they’re so easy that you may be tempted to use them even when you shouldn’t. Make sure that your use case is actually appropriate for your entire game to share the same value for that thing; if not, it shouldn’t be static.

1 Like

@StarManta Thanks StarManta. So, if I declare a static member of a class/object, I can create multiple instances of that class and have multiple static members within a class?

Also, say I have nested lists of classes within a class, how would I cut that down to size?

myMainStaticGameObject.sceneList[0].objectList[0].hp = 5;

Is there a way to shorten that in code and reference in a script just the particular objectList[0] without using a new keyword (since it’s a list, I just want to reference it within another class, not create a new copy of it to change).

Why does the monobehaviour need to access the list of strings? If MyFirstClass contains the strings then it should be the one to alter/find/iterate them as well.

Then if every MySecondClass will use a MyFirstClass with the same values, make MyFirstClass instance static so there is one instance shared between all of the MySecondClass behaviours.

There are a tonne of solutions to your problem, but it is impossible to know what one is right without the actual code.

1 Like

http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
This article might open your eyes a bit to how a game structure should work.

There should not be a static manager in the scene that objects rely on, game objects are supposed to be self-contained entities that do everything for themselves. They can find a manager type object themselves but there needs to be some level of abstraction so they don’t actually rely on the manager (this is where interfaces are useful).

1 Like

I think I finally understand.

In my main game data class I need to make methods that I can use throughout the game.

I think the most basic concept for you to understand is that there is only one list, the one in the first class instance. If you have 1000 other classes which reference it, then you have one list, and 1000 references to that list. Any changes in that original list will be available to all of those other classes through the reference. The reference itself is inconsequential in terms of memory required to store it. There is no need to make the list static UNLESS you need to ensure that multiple instances of that first class (the one where the list is defined) will all use the same list.

Regarding the use of static variables and singletons, you are correct that they are generally frowned upon from an OOP standpoint, however they are commonly used in game development (look at the Unity engine for example as well as other game engines). There are use cases for them that arise due both to reasons of practicality and performance. Arguments to the contrary border on religion…

Lastly, regarding your question about whether “new” should be avoided, the answer is that it depends. Clearly it would be a bad idea to create new instances of a class during a frame update only to have them discarded at the end of the frame. You’ll notice that in the context of Unity, this is generally not done. The creation of constructs during a frame update, such as creating a new Vector3 struct to create a new position to assign back to a transform are limited to structs and other value types so the overhead is inconsequential.

1 Like

Yep, ChazBass is right though. Static classes and Singletons are not the best approaches. If you haven’t already, look into ScriptableObjects for data classes. This would make your data class into an asset that can easily be swapped out for a different one if need be.

2 Likes

Gotcha, alright thanks guys this helped quite a bit to clarify.

@ChazBass

I think this is exactly what I’m not getting.

public class MyFirstClass {
  List<string> myList = new List<string>();
}

//then...
public class MySecondClass {
  List<string> myFirstClassList = new List<string>();
  MyFirstClass myFirstClass = new MyFirstClass();
 
  Start() {
    myFirstClassList = myFirstClass.myList;
    //and from here on can I just edit myFirstClassList (and it will make changes to myFirstClass.myList)?
    //I think it is now a reference, right?
  }

}

So even though I’m using the new keyword, it doesn’t take up more memory like that than if I edited the values within MySecondClass? Or it’s just always better to make methods within MyFirstClass and access them through MySecondClass? (like below)

public class MyFirstClass {
  List<string> myList = new List<string>();

  public int GetMyListCount() {
     return myList.Count;
  }

}

//then...
public class MySecondClass {
  MyFirstClass myFirstClass = new MyFirstClass();

  Start() {
     int testListCount = myFirstClass.GetMyListCount();
  }

}

There are 2 lists… but the second list is now unreferenced and will be collected by the garbage collector.

Don’t instantiate the second list.

1 Like

So something like:

private List<string> myFirstClassList;

Instead of:

private List<string> myFirstClassList = new List<string>();

There are a bunch of things going on here.

First you want to do some study on the difference between a class and an instance. You also want to look up the difference between a value type and a reference type. Both of these ideas are fundamental to C#, and without them, none of the rest of the discussion will make sense.

At runtime the classes you’ve written don’t actually exist. Classes are a blueprint. You can use a class to create an instance, normally with new. Each instance normally operates completely independent of every other instance, with its own set of variables and state.

These instances often need to talk to each other. Which is normally done via references. A reference allows one instance to communicate with another instance via its public methods and variables.

There are a bunch of ways to get a reference to another instance. You get one when you create a new instance. You can pass around references when you create a new instance. Or you can pass them in via a method or variable. Unity also gives you a bunch of ways to get references, including GetComponent, Find, OnCollisionXXX and the inspector.

You can also get a reference using static, as has been mentioned in this thread. This is possibly the worst way to get a reference. You should avoid it like the plague until you understand all the other methods well.

1 Like

@Kiwasi

Thanks for the info. : ) What I’m understanding now is that when I write a class, make methods within that class that access it’s own data/values, then using a created instance of that class call the method to change the values like myClassOne.increaseHealth(1);

What I was doing was making classes without methods. These classes would just values that act as like containers of data, but as a beginner in development my brain for some reason slipped the thought that you can add methods to these classes.

It appears that there’s some confusion over the “new” keyword, so I thought I’d help clarify this bit.

Simply typing:

MyClassFirst myClassFirst;

does not create an instance. The value of myClassFirst is null. So if you were to try to access its contents, you’d get an error (or exception). All you’re doing is declaring it as a class member, so it can be referenced by any of the class methods.

That’s why the first thing you should do is to create an instance in the Start() function (using the new keyword) before it can be safely used by the class. Or you could just do

MyClassFirst myClassFirst = new MyClassFirst();

and skip creating an instance in Start().