在c#中对一个类型的每个实例调用一个方法

本文关键字:一个 实例 调用 方法 类型 | 更新日期: 2023-09-27 18:18:35

我知道你可以调用一个实例方法来执行每个对象。我还知道,你可以在类型上有一个静态方法,可以从类型调用。

但是,如何调用对特定类型的每个实例都起作用的方法(例如,将成员变量设置为0)?

在c#中对一个类型的每个实例调用一个方法

c#没有提供直接的机制来跟踪所有可访问的对象,并且几乎从来没有一个好的理由想要这样的自动跟踪功能(而不是,比如说,一个你自己管理的显式池)。

但是要直接回答你的要求,你需要:

  1. 手动跟踪该类型的所有可访问实例(可能使用一组弱引用来防止跟踪器本身延长对象的生存期)。
  2. 提供一种机制(例如)对该集合的每个成员执行副作用。
  3. 当对象被销毁时,从集合中删除相关的弱引用。这对于防止弱引用泄漏是必要的。

所有这些都必须以线程安全的方式完成。

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);
        }
    }
}

你确定你需要这些吗?这真的很奇怪,而且不确定(会受到垃圾收集发生时间的严重影响)。

如果你可以修改你正在谈论的类型,你可以在该类中创建一个静态列表,在该类中保存每个创建的对象的引用。

当你要运行你的方法时,你只需要循环遍历所有的列表并运行你想要的。

如果你不能修改这个类型来创建这个List,你不能没有一些技巧,我可以建议你使用工厂模式,这样你仍然可以保留该类型对象的List,只要你使用那个工厂。

注意:如果你不打算用[]操作符访问列表(我的意思是通过索引),而只是通过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表达式在所有这些实例上执行一个方法,也有其他的方法,但这是美丽的:

MyFactory f = new MyFactory();
for (int i = 0; i < 5; i++)
    f.Create();
f.Execute((obj, param) =>
{
    //Do something
}, null);

* 编辑:* (本·沃伊特评论)

弱引用方式,继续使用垃圾收集:

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查看它的用法