I know that you can call an instance method that executes for each object. I also know that you can have a static method on the type that is callable from the type.
But how would one call a method that acts on every instance of a particular type (say, to set a member variable to zero, for example)?
C# doesn't provide a direct mechanism to track all reachable objects and there's almost never a good reason to want such automatic tracking functionality (rather than, say, an explicit pool that you manage yourself).
But to answer your requirement directly, you'll need to:
All of this will have to be done in a thread-safe manner.
public class Foo
{
private static readonly HashSet<WeakReference> _trackedFoos = new HashSet<WeakReference>();
private static readonly object _foosLocker = new object();
private readonly WeakReference _weakReferenceToThis;
public static void DoForAllFoos(Action<Foo> action)
{
if (action == null)
throw new ArgumentNullException("action");
lock (_foosLocker)
{
foreach (var foo in _trackedFoos.Select(w => w.Target).OfType<Foo>())
action(foo);
}
}
public Foo()
{
_weakReferenceToThis = new WeakReference(this);
lock (_foosLocker)
{
_trackedFoos.Add(_weakReferenceToThis);
}
}
~Foo()
{
lock (_foosLocker)
{
_trackedFoos.Remove(_weakReferenceToThis);
}
}
}
Are you sure you need all of this though? This is all really strange and non-deterministic (will be heavily impacted by when garbage-collection occurs).
If you can modify the type you are talking about, you can create a static List in that class where you keep a reference of every object created.
When you'll run your method, you just have to loop over all that list and run what you want.
If you can't modify that type so you can create this List, you can't do it without some hacks, I can suggest you using the Factory pattern, so you can still keep a List of objects of that type, provided that you use that factory.
Note: If you are not going to access the list with [ ] operator (through an index I mean) but only through a foreach, I suggest you to use a LinkedList which will be far more efficient in this case (lot of add/remove operations, no random access and you'll avoid array resize like list does).
Example:
using System.Linq.Expressions;
class MyClassFactory
{
LinkedList<MyClass> m_Instances = new LinkedList<MyClass>();
MyClass Create()
{
m_Instances.AddLast(new MyClass());
return m_Instances.Last.Value;
}
void Destroy(MyClass obj)
{
m_Instances.Remove(obj);
}
void Execute(Expression<Action<MyClass, object>> expr, object param)
{
var lambda = expr.Compile();
foreach (var obj in m_Instances)
lambda(obj, param);
}
}
You can then easily instanciate and use always that factory to instanciate your class. It's not a perfect solution, but it's a clean approach to at least work with your problem.
You can use lambda expressions to execute a method on all those instances, there are also other approaches but that is beautiful:
MyFactory f = new MyFactory();
for (int i = 0; i < 5; i++)
f.Create();
f.Execute((obj, param) =>
{
//Do something
}, null);
*Edit: * (about Ben Voigt comment)
Weak reference approach, to keep using garbage collection:
using System.Linq.Expressions;
class MyClassFactory
{
HashSet<WeakReference> m_Instances = new HashSet<WeakReference>();
MyClass Create()
{
var obj = new MyClass();
m_Instances.Add(new WeakReference(obj));
return obj;
}
void Execute(Expression<Action<MyClass, object>> expr, object param)
{
var lambda = expr.Compile();
// Hope syntax is ok on this line
m_Instances.RemoveWhere(new Predicate<WeakReference>(obj => !obj.IsAlive));
foreach (var obj in m_Instances)
lambda(obj, param);
}
}
Check RemoveWhere to see it's usage
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With