Согласно комментариям: вот как это можно сделать из CIL, который можно сгенерировать из C#.
Я надеялся использовать DynamicMethod
, но мне не удалось заставить это работать без создания пользовательского типа делегата во время выполнения, поэтому вместо этого мне нужно было использовать AssemblyBuilder
.
using System;
using System.Reflection;
using System.Reflection.Emit;
public delegate void CallBadFunction(Delegate d, Callback c);
public delegate void Callback(ref int i);
static class Program
{
static int i;
static object BadMethod()
{
return i;
}
static MethodInfo GetBadMethod()
{
return typeof(Program).GetMethod("BadMethod", BindingFlags.Static | BindingFlags.NonPublic);
}
static void Main()
{
var badMethod = GetBadMethod();
var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("-"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("-");
var badDelegate = module.DefineType("BadDelegateType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(MulticastDelegate));
var badDelegateCtor = badDelegate.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) });
badDelegateCtor.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
var badDelegateInvoke = badDelegate.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.HideBySig, typeof(int).MakeByRefType(), Type.EmptyTypes);
badDelegateInvoke.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
var badDelegateType = badDelegate.CreateType();
var method = module.DefineGlobalMethod("-", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(Delegate), typeof(Callback) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, badDelegate);
il.Emit(OpCodes.Callvirt, badDelegateInvoke);
il.Emit(OpCodes.Callvirt, typeof(Callback).GetMethod("Invoke"));
il.Emit(OpCodes.Ret);
module.CreateGlobalFunctions();
var callBadFunction = (CallBadFunction)Delegate.CreateDelegate(typeof(CallBadFunction), module.GetMethod("-"));
callBadFunction(badMethod.CreateDelegate(badDelegateType), (ref int i) =>
{
i++;
});
}
}
После компиляции этой программы используйте ILDASM для ее дизассемблирования и замените определение BadMethod
на
.method private hidebysig static int32&
BadMethod() cil managed
{
ldsflda int32 Program::i
ret
}
Это превращает его в функцию, возвращающую int32&
, которую затем сможет вызвать следующий код. Единственное место, где C# допускает типы int32&
, находится в параметрах функции (ref int
), поэтому, чтобы сделать результат пригодным для использования, я использовал функцию обратного вызова, которой передается возвращаемое значение BadMethod
.
person
Community
schedule
28.04.2014
ByRef
, типыByRef
не являются объектами, а возвращаемый типmethd.Invoke
—object
, поэтому у него не будет возможности вернуть результат. Должна быть возможность использовать тип делегата, который имеет возвращаемый типByte&
, а затем использоватьMethodInfo.CreateDelegate
для создания экземпляра этого типа делегата, но такой тип делегата также нельзя написать на C#. Я не вижу выхода из этого, кроме как не использовать C#. ЕслиDynamicMethod
, построенный на C#, приемлем (лично я бы предпочел его C++/CLI), я могу опубликовать ответ, используя его. - person   schedule 28.04.2014