2011-12-23 27 views
3

我知道你可以調用一個爲每個對象執行的實例方法。我也知道你可以在類型中調用類型的靜態方法。在c中調用每種類型的實例的方法#

但是,如何調用一個方法作用於特定類型的每個實例(例如,將成員變量設置爲零)?

+0

目前尚不清楚你的意思。你能提供一個例子嗎? – Ani 2011-12-23 04:36:48

+1

將非靜態方法發送到對象的唯一方法是具有所述目標對象。 C#/ .NET不會自動跟蹤「類型X的所有實例」。通常有一個對象集合,比如'List myItems = ...',然後對所有可用的元素執行操作,比如'foreach(myItems中的var item){item.ClearIt(); }'。請注意,項目需要手動放入'myItems' *。 – 2011-12-23 04:37:30

+1

簡短的回答,你不能。 – 2011-12-23 04:39:37

回答

5

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

你確定你需要所有這些嗎?這真是奇怪而且不確定(當垃圾收集發生時會受到嚴重影響)。

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

* 編輯:*(約本福格特評論)

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

+2

這打破垃圾收集。 – 2011-12-23 05:03:19

+0

有一種銷燬方法,這就是工廠應該如何工作。如果你不刪除這些實例,這是你的錯誤。如果你不用C++調用delete,你會在你的堆上創建問題,這裏是一樣的。 – 2011-12-23 05:06:50

+0

要求手動銷燬每個實例與垃圾收集相反。 – 2011-12-23 05:08:59

相關問題