#c# #delegates #garbage-collection #farseer
#c# #делегирует #сбор мусора #дальновидный
Вопрос:
Возможно ли вызвать MulticastDelegate
и обработать возвращаемое значение каждого подключенного обработчика без выделения какой-либо памяти?
Предыстория
В схеме обычных вещей Delegate[]
выделенное by MulticastDelegate.GetInvocationList()
незначительно. Однако в некоторых случаях важно минимизировать выделения. Например, во время игрового процесса в играх Xbox, работающих на compact framework, каждый выделенный 1 МБ будет вызывать сбор и неприятную заминку с частотой кадров.
После использования CLR Profiler для поиска и устранения большинства выделений во время игрового процесса у меня остается 50% мусора, вызванного вызовами обратного вызова столкновения с Farseer Physics. Необходимо выполнить итерацию полного списка вызовов, поскольку пользователь может вернуться false
, чтобы отменить ответ на столкновение от любого из подключенных обработчиков (а вызов делегата без использования GetInvocationList()
просто возвращает результат последнего подключенного обработчика).
Для справки, вот код Farseer, о котором идет речь:
// Report the collision to both participants. Track which ones returned true so we can
// later call OnSeparation if the contact is disabled for a different reason.
if (FixtureA.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
enabledA = handler(FixtureA, FixtureB, this) amp;amp; enabledA;
Комментарии:
1. Я почти уверен, что большую часть времени список вызовов будет представлять собой всего одну функцию, поэтому, если бы была хотя бы
Delegate.Count
функция, мы могли бы оптимизировать ее, не повторяя список в этом случае.2. Кто бы ни проголосовал против вопроса, по крайней мере, проявите порядочность, чтобы объяснить, почему.
3. В идеале вам следует перепроектировать свою программу так, чтобы события не должны возвращать значение, именно потому, что получение значений, возвращаемых из события, является громоздким. Пусть ваши обработчики вызовут метод экземпляра, запускающего событие, или изменят класс, переданный в качестве параметра обработчику события, вместо того, чтобы возвращать значение.
4. Спасибо Servy, это имеет смысл. Может быть нелегко убедить разработчиков Farseer изменить свой API таким образом, но тогда это может быть единственным способом избежать мусора.
5. Вы можете взглянуть на реализацию
GetInvocationList
here . Похоже, вам придется использовать отражение для доступа_invocationCount
к и_invocationList
, но после доступа к ним это должно быть довольно тривиально.