我知道您可以调用为每个对象执行的实例方法。我也知道你可以在类型可调用的类型上使用静态方法。
但是如何调用一个作用于特定类型的每个实例的方法(例如,将成员变量设置为零)?
答案 0 :(得分:6)
C#没有提供跟踪所有可到达对象的直接机制,并且几乎没有理由想要这样的自动跟踪功能(而不是,例如,您自己管理的显式池)
但要直接回答您的要求,您需要:
所有这一切都必须以线程安全的方式完成。
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);
}
}
}
你确定你需要所有这些吗?这一切都非常奇怪且非确定性(将在垃圾收集发生时受到严重影响。)
答案 1 :(得分:1)
如果您可以修改您正在讨论的类型,您可以在该类中创建一个静态列表,您可以在其中保留对所创建的每个对象的引用。
当你运行你的方法时,你只需要遍历所有列表并运行你想要的。
如果您无法修改该类型以便创建此列表,则无法在没有任何黑客的情况下执行此操作,我建议您使用Factory pattern,这样您仍然可以保留一个对象列表该类型,只要您使用该工厂。
注意:如果您不打算使用[]运算符访问列表(通过索引我的意思),但只能通过foreach,我建议您使用LinkedList在这种情况下会更有效率(很多添加/删除操作,没有随机访问,你会避免像列表一样调整数组大小)。
示例:强>
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);
}
}
然后,您可以轻松实现并始终使用该工厂来实现您的课程。 这不是一个完美的解决方案,但它至少可以解决您的问题。
您可以使用lambda expressions在所有这些实例上执行方法,还有其他方法,但这很漂亮:
MyFactory f = new MyFactory();
for (int i = 0; i < 5; i++)
f.Create();
f.Execute((obj, param) =>
{
//Do something
}, null);
* 编辑:* (关于Ben Voigt评论)
Weak reference方法,继续使用垃圾收集:
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);
}
}
检查RemoveWhere以查看其使用情况