Per i commenti: ecco come può essere eseguito da CIL, che può essere generato da C#.
Speravo di utilizzare un DynamicMethod
, ma non riesco a farlo funzionare senza creare un tipo di delegato personalizzato in fase di runtime, quindi ho dovuto usare AssemblyBuilder
invece.
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++;
});
}
}
Dopo aver compilato questo programma, utilizzare ILDASM di smontarlo, e sostituire la definizione BadMethod
s' da
.method private hidebysig static int32&
BadMethod() cil managed
{
ldsflda int32 Program::i
ret
}
Questo lo trasforma in una funzione che restituisce int32&
, che il seguente codice quindi gestire a chiamare . L'unica posizione C# consente i tipi int32&
nei parametri di funzione (ref int
), quindi per rendere utilizzabile il risultato, ho utilizzato una funzione di richiamata, che ottiene il valore restituito di BadMethod
.
Interessante, ma l'eccezione sembra abbastanza chiara: la funzione restituisce un riferimento a un byte e l'invocazione non supporta le funzioni che restituiscono riferimenti (perché, non lo so ... forse nel caso in cui qualcosa sullo stack sia restituita). Il metodo è pubblico, forse potrebbe essere chiamato tramite una DLL C++ gestita? –
@ T.Kiley - d'accordo, l'eccezione è chiara, ad esempio "Non supportato". Ma la mia domanda è come aggirare. Sì, forse C++ DLL farebbe, ma mi piacerebbe aggirare in C# se possibile. Aggiornerò la domanda Grazie. – Les
Sarebbe opportuno che i Descriptors valgano un mooch a. So che forniscono ulteriori capacità di metadati per riflessione, sono sicuro che ci siano anche alcune cose di invocazione. – brumScouse