Делегаты в MSIL
От: AndrewStrelkov  
Дата: 20.02.09 10:57
Оценка:
Всем доброго времени суток.
Разбирая код IL натолкнулся на следующую строку:
IL_001d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)

Нужно повторить это в динамической генерации кода. Но так как делегат нельзя создать, просто написав
(OpCodes.Newobj, typeof(EventHandler).GetConstructor(Type.EmptyTypes))

то тут возникла серьезная проблема. Буду благодарен, если кто сможет разъяснить, в чем моя ошибка и как все-таки создать делегат.
Re: Делегаты в MSIL
От: nikov США http://www.linkedin.com/in/nikov
Дата: 20.02.09 11:18
Оценка:
Здравствуйте, AndrewStrelkov, Вы писали:

AS>
AS>IL_001d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
AS>

AS>Нужно повторить это в динамической генерации кода. Но так как делегат нельзя создать, просто написав
AS>
AS>(OpCodes.Newobj, typeof(EventHandler).GetConstructor(Type.EmptyTypes))
AS>


А откуда Type.EmptyTypes? Там же два параметра в сигнатуре, с типами object и System.IntPtr.
Только потом с динамической генерацией аккуратнее. Для вызовов конструкторов делегатов более строгие правила верификации (описано в Ecma-335).
Re[2]: Делегаты в MSIL
От: AndrewStrelkov  
Дата: 20.02.09 15:23
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, AndrewStrelkov, Вы писали:


AS>>
AS>>IL_001d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
AS>>

AS>>Нужно повторить это в динамической генерации кода. Но так как делегат нельзя создать, просто написав
AS>>
AS>>(OpCodes.Newobj, typeof(EventHandler).GetConstructor(Type.EmptyTypes))
AS>>


N>А откуда Type.EmptyTypes? Там же два параметра в сигнатуре, с типами object и System.IntPtr.

N>Только потом с динамической генерацией аккуратнее. Для вызовов конструкторов делегатов более строгие правила верификации (описано в Ecma-335).

Все правильно, в делегат передается указатель на функцию по сигнатуре. Вызов с параметром конструктора Type.EmtyTypes создает делегат без указателя, и это правильно вызывает исключение NullReferenceException. Но такое же исключение возникает при вызове с параметрами (new Type[]{ typeof(IntPtr)}).

А в стандарте Ecma-335 описано почти все то же, как в MSDN.
Re[3]: Делегаты в MSIL
От: Пельмешко Россия blog
Дата: 20.02.09 15:50
Оценка: +1
Здравствуйте, AndrewStrelkov, Вы писали:

AS>Все правильно, в делегат передается указатель на функцию по сигнатуре. Вызов с параметром конструктора Type.EmtyTypes создает делегат без указателя, и это правильно вызывает исключение NullReferenceException. Но такое же исключение возникает при вызове с параметрами (new Type[]{ typeof(IntPtr)}).


Вызывать всё же надо с двумя параметрами, согласно сигнатуре конструктора...
gen.Emit(OpCodes.Newobj, typeof( EventHandler ).GetConstructor( new[] { typeof( object ), typeof( IntPtr ) } ));

Перед этим загрузив в стек null если передаваемый делегату метод является статическим, или ссылку на инстанс, если передаётся метод экземпляра, а потом уже загрузив в стек указатель на сам метод...
У меня создалось
Re[3]: Делегаты в MSIL
От: nikov США http://www.linkedin.com/in/nikov
Дата: 20.02.09 16:10
Оценка:
Здравствуйте, AndrewStrelkov, Вы писали:

AS>>>
AS>>>IL_001d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
AS>>>

AS>>>Нужно повторить это в динамической генерации кода. Но так как делегат нельзя создать, просто написав
AS>>>
AS>>>(OpCodes.Newobj, typeof(EventHandler).GetConstructor(Type.EmptyTypes))
AS>>>


AS>Все правильно, в делегат передается указатель на функцию по сигнатуре. Вызов с параметром конструктора Type.EmtyTypes создает делегат без указателя, и это правильно вызывает исключение NullReferenceException. Но такое же исключение возникает при вызове с параметрами (new Type[]{ typeof(IntPtr)}).


У конструктора два параметра. Поэтому надо передавать массив из двух типов (а не из нуля или одного).
Re[4]: Делегаты в MSIL
От: AndrewStrelkov  
Дата: 20.02.09 16:11
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Здравствуйте, AndrewStrelkov, Вы писали:


AS>>Все правильно, в делегат передается указатель на функцию по сигнатуре. Вызов с параметром конструктора Type.EmtyTypes создает делегат без указателя, и это правильно вызывает исключение NullReferenceException. Но такое же исключение возникает при вызове с параметрами (new Type[]{ typeof(IntPtr)}).


П>Вызывать всё же надо с двумя параметрами, согласно сигнатуре конструктора...

П>
П>gen.Emit(OpCodes.Newobj, typeof( EventHandler ).GetConstructor( new[] { typeof( object ), typeof( IntPtr ) } ));
П>

П>Перед этим загрузив в стек null если передаваемый делегату метод является статическим, или ссылку на инстанс, если передаётся метод экземпляра, а потом уже загрузив в стек указатель на сам метод...
П>У меня создалось

Вот как у меня собсвенно, все выглядит:

dynMenuConstructorGetIL.Emit(OpCodes.Ldarg_0);
foreach (MethodBuilder m in methodsStorage)
{
    if ("call_" + ((MethodInfo)root.Tag).Name.ToString() == m.Name.ToString())
    {
        dynMenuConstructorGetIL.Emit(OpCodes.Ldftn, m);
        break;
    }
}
dynMenuConstructorGetIL.Emit(OpCodes.Newobj, typeof(Delegate).GetConstructor(new Type[] {typeof(object), typeof(IntPtr)}));


Вначале передаю ссылку на this, потом загружаю указатель на метод и только потом уже вызываю конструктор делегата.
Re[4]: Делегаты в MSIL
От: AndrewStrelkov  
Дата: 20.02.09 16:13
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, AndrewStrelkov, Вы писали:


AS>>>>
AS>>>>IL_001d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
AS>>>>

AS>>>>Нужно повторить это в динамической генерации кода. Но так как делегат нельзя создать, просто написав
AS>>>>
AS>>>>(OpCodes.Newobj, typeof(EventHandler).GetConstructor(Type.EmptyTypes))
AS>>>>


AS>>Все правильно, в делегат передается указатель на функцию по сигнатуре. Вызов с параметром конструктора Type.EmtyTypes создает делегат без указателя, и это правильно вызывает исключение NullReferenceException. Но такое же исключение возникает при вызове с параметрами (new Type[]{ typeof(IntPtr)}).


N>У конструктора два параметра. Поэтому надо передавать массив из двух типов (а не из нуля или одного).


Разными способами уже старался. Но все равно выбрасывается исключение.
Re[5]: Делегаты в MSIL
От: AndrewStrelkov  
Дата: 20.02.09 16:21
Оценка:
Здравствуйте, AndrewStrelkov, Вы писали:

AS>Здравствуйте, Пельмешко, Вы писали:


П>>Здравствуйте, AndrewStrelkov, Вы писали:


AS>>>Все правильно, в делегат передается указатель на функцию по сигнатуре. Вызов с параметром конструктора Type.EmtyTypes создает делегат без указателя, и это правильно вызывает исключение NullReferenceException. Но такое же исключение возникает при вызове с параметрами (new Type[]{ typeof(IntPtr)}).


П>>Вызывать всё же надо с двумя параметрами, согласно сигнатуре конструктора...

П>>
П>>gen.Emit(OpCodes.Newobj, typeof( EventHandler ).GetConstructor( new[] { typeof( object ), typeof( IntPtr ) } ));
П>>

П>>Перед этим загрузив в стек null если передаваемый делегату метод является статическим, или ссылку на инстанс, если передаётся метод экземпляра, а потом уже загрузив в стек указатель на сам метод...
П>>У меня создалось

AS>Вот как у меня собсвенно, все выглядит:


AS>
AS>dynMenuConstructorGetIL.Emit(OpCodes.Ldarg_0);
AS>foreach (MethodBuilder m in methodsStorage)
AS>{
AS>    if ("call_" + ((MethodInfo)root.Tag).Name.ToString() == m.Name.ToString())
AS>    {
AS>        dynMenuConstructorGetIL.Emit(OpCodes.Ldftn, m);
AS>        break;
AS>    }
AS>}
AS>dynMenuConstructorGetIL.Emit(OpCodes.Newobj, typeof(Delegate).GetConstructor(new Type[] {typeof(object), typeof(IntPtr)}));
AS>


AS>Вначале передаю ссылку на this, потом загружаю указатель на метод и только потом уже вызываю конструктор делегата.


Вопрос отпал, я и сам не заметил, что пытаюсь вызвать конструктор Delegate, а не EventHandler .
Чтоб меня, спасибо всем за советы!
Re[5]: Делегаты в MSIL
От: Пельмешко Россия blog
Дата: 20.02.09 16:23
Оценка:
Здравствуйте, AndrewStrelkov, Вы писали:

AS>Разными способами уже старался. Но все равно выбрасывается исключение.


dynMenuConstructorGetIL.Emit(OpCodes.Newobj, typeof(Delegate).GetConstructor(new Type[] {typeof(object), typeof(IntPtr)}));


Конечно
Смотрите чей вы конструктор ищите, почему typeof( Delegate ), а не typeof( EventHandler )?
Re[6]: Делегаты в MSIL
От: AndrewStrelkov  
Дата: 20.02.09 19:29
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Здравствуйте, AndrewStrelkov, Вы писали:


AS>>Разными способами уже старался. Но все равно выбрасывается исключение.


П>
П>dynMenuConstructorGetIL.Emit(OpCodes.Newobj, typeof(Delegate).GetConstructor(new Type[] {typeof(object), typeof(IntPtr)}));
П>


П>Конечно

П>Смотрите чей вы конструктор ищите, почему typeof( Delegate ), а не typeof( EventHandler )?

Все верно, уже обнаружил ошибку. Благодарю всех, все успешно работает!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.