Можете ли вы создать делегат метода экземпляра без указания экземпляра во время создания? Другими словами, можете ли вы создать «статический» делегат, который принимает в качестве первого параметра экземпляр, к которому должен вызываться метод?
Например, как я могу создать следующий делегат, используя отражение?
Func<int, string> = i=>i.ToString();
Мне известно о том, что я могу использовать methodInfo.Invoke, но это медленнее и не проверяет правильность типа до тех пор, пока он не будет вызван.
Если у вас есть MethodInfo
определенного статического метода , можно создать делегат, используя Delegate.CreateDelegate(delegateType, methodInfo)
, и все параметры статического метода останутся свободными.
Как указал Джон Скит, вы можете просто применить то же самое, чтобы создать открытый делегат метода экземпляра, если метод не виртуален для ссылочного типа. Решить, какой метод вызывать для виртуального метода, сложно, поэтому это не так тривиально, и типы значений выглядят так, как будто они не работают вообще.
Для типов значений CreateDelegate
демонстрирует очень странное поведение:
var func37 = (Func<CultureInfo,string>)(37.ToString);
var toStringMethod = typeof(int).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(CultureInfo) }, null);
var func42 = (Func<CultureInfo,string>)Delegate.CreateDelegate(typeof(Func<CultureInfo,string>), 42, toStringMethod,true);
Console.WriteLine( object.ReferenceEquals(func37.Method,func42.Method)); //true
Console.WriteLine(func37.Target);//37
Console.WriteLine(func42.Target);//42
Console.WriteLine(func37(CultureInfo.InvariantCulture));//37
Console.WriteLine(func42(CultureInfo.InvariantCulture));//-201040128... WTF?
Вызов CreateDelegate
с null
в качестве целевого объекта вызывает исключение привязки, если метод экземпляра принадлежит типу значения (это работает для ссылочных типов).
Несколько последующих лет спустя: Неправильно связанная цель, из-за которой func42(CultureInfo.InvariantCulture);
вернула "-201040128"
вместо "42"
в моем примере, была повреждением памяти, которое могло позволить удаленное выполнение кода ( CVE-2010-1898 ); это было исправлено в 2010 году в обновлении безопасности ms10-060 . Текущие рамки правильно печатать 42! Это не облегчает ответ на этот вопрос, но объясняет особенно странное поведение в примере.