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

时间:2011-12-23 04:35:23

标签: c# types methods instance

我知道您可以调用为每个对象执行的实例方法。我也知道你可以在类型可调用的类型上使用静态方法。

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

2 个答案:

答案 0 :(得分:6)

C#没有提供跟踪所有可到达对象的直接机制,并且几乎没有理由想要这样的自动跟踪功能(而不是,例如,您自己管理的显式池)

但要直接回答您的要求,您需要:

  1. 手动跟踪该类型的所有可到达实例(可能带有一组弱引用,以防止跟踪器本身延长对象的生命周期)。
  2. 提供一种机制(比方说)对该组的每个成员执行副作用。
  3. 当对象被销毁时,从集合中删除相关的弱引用。这对于防止弱参考泄漏是必要的。
  4. 所有这一切都必须以线程安全的方式完成。

    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以查看其使用情况