Ответ 1
Здесь более простой вариант - в основном, я использую конструктор "под капотом" в типе делегирования (тот, который использует IL), чтобы передать целевой объект с неправильной подписью и... он отлично работает (под которым я подразумеваю, что он не генерирует исключение - он ведет себя точно так же, как ваш код):
using System;
static class P
{
static void Main()
{
// resolve the (object, IntPtr) ctor
var ctor = typeof(Func<string, string>).GetConstructors()[0];
// resolve the target method
var mHandle = typeof(P).GetMethod(nameof(Concat))
.MethodHandle.GetFunctionPointer();
object target = null; // because: static
// create delegate instance
var del = (Func<string, string>)ctor.Invoke(new object[] { target, mHandle });
var result = del("abc");
Console.WriteLine(result); // "-abc"
}
public static string Concat(string s1, string s2)
{
return string.Format("{0}-{1}", s1, s2);
}
}
На самом деле это не объяснение. Но было бы полезно, если вы хотите спросить кого-то еще CLR-эксперта! Я бы ожидал, что конструктор делегата громко пожаловался, что цель неверна.
При догадках (чистая спекуляция) это случай: если вы передаете IntPtr
(native int), то вы полностью по своему усмотрению - код делает самую быструю вещь. Это похоже на неприятную ловушку для неосторожного, хотя!
Что касается того, почему s2
имеет значение, а s1
пусто: я думаю, это связано с тем, что стек сбрасывается (не вверх), поэтому в двухпараметрическом методе arg1
- это параметр немедленно смежный в предыдущую позицию в стеке. Когда мы передаем одно значение вместо двух, мы помещаем только одно значение, поэтому s2
имеет значение, а s1
- undefined (может быть мусор из предыдущего кода).