[英]Calling a method on every instance of a type in c#
我知道你可以調用為每個對象執行的實例方法。 我也知道你可以在類型可調用的類型上使用靜態方法。
但是,如何調用一個作用於特定類型的每個實例的方法(例如,將成員變量設置為零)?
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);
}
}
}
你確定你需要所有這些嗎? 這一切都非常奇怪且非確定性(將在垃圾收集發生時受到嚴重影響)。
如果您可以修改所討論的類型,則可以在該類中創建一個靜態列表,在該類中保留對創建的每個對象的引用。
當你運行你的方法時,你只需要遍歷所有列表並運行你想要的。
如果你不能修改那個類型以便你可以創建這個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.