Каковы размеры данных для событий и подписки на события?
Извиняюсь за то, что не успел примерить sizeof на мероприятии, но в духе усиления Google-фу....
Какой фактический объем памяти будет добавлен к экземпляру класса, который имеет поле события?
Какая фактическая память будет использоваться для каждой подписки на событие?
Я предполагаю отдельные указатели для каждого события или подписки, но я просто хочу быть уверен.
Рассмотрим этот пример:
public class VertexMovedArgs : EventArgs {
public Vertex theVert;
}
public class Vertex {
// what size does this add to each Vertex?
public event EventHandler<VertexMovedArgs> VertexMovedEvent;
private Vector3 m_pos;
public Vector3 pos {
get { return m_pos; }
set {
if ( value != m_pos ) {
m_pos = value;
EventHandler<VertexMovedArgs> tellEveryoneWeMoved = VertexMovedEvent;
if ( handler != null ) {
VertexMovedArgs args = new VertexMovedArgs( this );
tellEveryoneWeMoved( this, args );
}
}
}
}
}
public class Mesh {
private List<Vertex> m_verts = new List<Vertex>();
public Vertex AddVert() {
Vertex vert = new Vertex();
// what size per-subscription does this add to this Mesh instance (or elsewhere)?
vert.VertexMovedEvent += onVertexMoved;
m_verts.Add( vert );
}
void onVertexMoved( object sender, VertexMovedArgs args ) {
// play the vertex like a violin, etc...
}
}
2 ответа
Поле события - это просто ссылка на объект.
Пока вы не поместите обработчик (делегат) в него, он будет просто потреблять один размер указателя (4 или 8 байт) на экземпляр класса.
Экземпляр делегата имеет четыре поля размера указателя плюс стандартный заголовок объекта CLR.
Они хранят:
- Цель для вызова закрытого делегата
- MethodBase функции, указанной на
- Указатель на функцию для вызова
- Вспомогательный указатель, хранящий адрес фактической указанной функции (используется с открытыми делегатами для перестановки параметров)
Многоадресные делегаты (на практике все обычные делегаты) добавляют еще два:
- Массив делегатов, на которые указывает многоадресный делегат (
null
для одиноких делегатов) _invocationCount
(IntPtr
), используется по-разному для разных типов делегатов
Я нахожусь в процессе написания поста в блоге, который объяснит эти поля более подробно.
Событие - это пара методов для добавления и удаления подписок (на самом деле это три метода, но третий метод вообще ни для чего не используется). Сами события ничего не добавляют к размеру экземпляра объекта, но логика добавления / удаления обычно должна добавлять хотя бы одно поле. Наиболее распространенной реализацией события по умолчанию является создание поля типа MultiCastDelegate и использование Delegate.Combine для добавления подписок и Delegate.Remove для их удаления.