I have this example code which is incomplete because I don't know how to do what I'm trying to do.
// This class will never be garbage collected
// It is the core to my Game Engine Loop.
public class Application
{
HybridObject obj1;
HybridObject obj2;
List<Test> tests = new List<Test>();
public Application()
{
obj1 = new HybridObject();
obj2 = obj1;
for (int i = 0; i < 1000; i++)
{
Test test = new Test();
test.obj = obj1;
tests.Add(test);
}
obj1.Delete(); // This line should Null all properties using obj1 as a value.
while (true)
{
CheckIfNull();
}
}
void CheckIfNull()
{
if (obj1 == null) Console.WriteLine("Destroyed 1");
if (obj2 == null) Console.WriteLine("Destroyed 2");
foreach (var t in tests)
{
if (t.obj == null)
{
Console.WriteLine("Destroyed From List");
}
}
}
}
public class Test
{
public HybridObject obj;
}
public class HybridObject
{
public void Delete()
{
// SET ALL REFERENCES THAT POINT TO THIS HYBRIDOBJECT TO NULL
}
}
If we just abstract away the mess of my code. The question boils down to this, how do I set everything that used obj to null in the example below?
HybridObject obj = new HybridObject();
List<HybridObject > objects = new List<HybridObject>();
objects.Add(obj);
objects.Add(obj);
obj = null; // If I set this all obj's in the list would be null as well.
Now let me explain, I'm making a basic game engine.
I'm trying to set all references to the HybridObject I created to null using a Delete method. When I call obj1.Delete() the 'Application' obj1, obj2 properties and all the 'Test' obj properties need to be set to null because I set the obj1 property to a new HybridObject(), then set all the other property values such as obj2 to obj1.
When I call obj1.Delete(); everything that points to the (obj1)HybridObject should now become null. Then the HybridObject can be garbage collected eventually because of no more references. Settings obj1 = null; doesn't solve this problem because it wont set the other references to null.
The obj1 property can be passed anywhere like into another class property, a list, struct, etc. So how would I handle setting everything to null without manually tracking all the references? The HybridObject will never be destroyed because there will still be strong references to it.
So what if during the runtime of my application I've created millions of objects over time and none of them have been destroyed because of the strong references they hold. What if that one HybridObject I created in application 'obj1' is passed into millions of other places such as collections over time? (This is all theoretical of course)
The question is. How do I remove ALL references or pointers to an object so it can be garbage collected? I'm unsure if this is even possible.
I found a solution using reflection but it becomes really complex when considering how HybridObject could be stored such as properties, collections, structs, etc, then it has to run over EVERY object instance I've created at runtime. It's not very fast so I don't think this is a good idea.
Tried creating an object Instance property inside of HybridObject, then making everything reference that Instance property, when I set that Instance property to null I wanted all things that pointed to that Instance property to reflect that change and become null. But I couldn't get it working.
I'm comfortable with from using Unity which allows this type of behaviour
Unity is a completely different runtime where null check is not actually checking if the reference is a null reference (i.e. it points to "empty memory") - see for example this answer, i.e. 1) it does not mean that all memory occupied by the object can be GCed (hence all the problems you can have in "vanilla" C# which you are trying to avoid) 2) it is possible to get true
for this == null
(see this SO question) which is something that does not make much sense from "vanilla" C# point of view.
its easy to avoid if you just do a check if object != null.
If what you are asking for would be possible, it would not be easy to avoid. Especially in multithreaded environment. Hence if any reference can be nullified at any moment there is no way to guarantee that after the check the reference is not actually null (unless using some magic locking which can potentially kill all performance and cause deadlocks).
So in summary, for anything that inherits UnityEngine.Object
comparison with null does not mean what you think it actually means, so you can consider following options:
==
which will "fake" nulls.
IDisposable
pattern for this (maybe with a small difference with usual implementation - not throwing when something is called on disposed object but making it no-op, but that is debatable)obj1.OnDelete
so the user code can do what is necessary, though I would argue that it can quickly become too cumbersomeRead more: