I wonder whether Action<T>
prevents an enclosing class instance to be garbage collected when all other references to such class instance are removed during runtime?
public class Class1
{
private Action<string> _callback;
public Class1(Action<string> callback)
{
_callback = callback;
}
public void DoSomething(string msg)
{
_callback(msg);
}
}
public class Class2
{
private List<Class1> _class1s;
public Class2()
{
_class1s = new List<Class1>();
}
public void AddClass1Instance()
{
_class1s.Add(new Class1(OnClass1DoSomething));
}
public void RemoveLastClass1Instance()
{
if(_class1s.Count > 0)
{
_class1s.RemoveAt(_class1s.Count - 1);
}
}
private void OnClass1DoSomething(string msg)
{
}
}
In this simplistic example, when I call RemoveLastClass1Instance()
within Class2
will the Class1
instance be garbage collected or does it remain to hold reference to OnClass1DoSomething()
via Action<string>
? My goal is to completely remove Class1
instances and have them garbage collected.
EDIT: (further to Jon Skeet's comments, I added the following code to better understand
public class Class1
{
public event Action<string> Event;
public Class1()
{
}
public void DoSomething(string msg)
{
var handle = Event;
if (handle != null)
{
handle(msg);
}
}
}
public class Class2
{
private List<Class1> _class1s;
public Class2()
{
_class1s = new List<Class1>();
}
public void AddClass1Instance()
{
var newClass1Instance = new Class1();
newClass1Instance.Event += OnClass1DoSomething;
_class1s.Add(newClass1Instance);
}
public void RemoveLastClass1Instance()
{
if(_class1s.Count > 0)
{
_class1s.RemoveAt(_class1s.Count - 1);
}
}
private void OnClass1DoSomething(string msg)
{
}
}
I wonder whether
Action<T>
prevents an enclosing class instance to be garbage collected when all other references to such class instance are removed during runtime?
No. If the delegate instance were still referenced elsewhere, and it had a target of the Class1
instance, then it would prevent the instance of Class1
from being garbage collected - but as it is, the target of the Action<string>
is an instance of Class2
.
Basically, there's nothing magical about delegates when it comes to garbage collection. If the delegate refers to an instance method, the target of that instance is held as a reference... so if the delegate is still reachable, the target of the delegate is still reachable. In your case, the delegate itself isn't reachable, and you're apparently not worried about whether or not the Class2
instance can be garbage collected.
The change to use an event doesn't affect this at all - it's still the instance of Class1
having a reference (via the delegate) to the original instance of Class2
... the only reference to the Class1
instance from Class2
is via the list.
See more on this question at Stackoverflow