簡體   English   中英

在c#中的每個類型實例上調用方法

[英]Calling a method on every instance of a type in 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,你不能沒有一些黑客攻擊,我可以建議你使用Factory模式 ,所以你仍然可以保留這種類型的對象列表,前提是你用那個工廠。

注意 :如果您不打算使用[]運算符訪問列表(通過索引我的意思),但只能通過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);

* 編輯:* (關於Ben Voigt評論)

弱參考方法,繼續使用垃圾收集:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM