I am trying to write a Method that returns that a DynamicMethod which when Invoked sets the first parameter to an object of Type T, This Object is called Value and is set when the class is instantiated, This is the code i've got right now:
using HarmonyLib;
using System.Reflection;
using System.Reflection.Emit;
public class OriginalCode<T>
{
public delegate void PostFix(ref T __result);
public T Value { get; set; }
public OriginalCode(T value)
{
Value = value;
}
public MethodInfo Postfix()
{
var result = new DynamicMethod("NewPostfix", typeof(void), new Type[] { typeof(T).MakeByRefType() }, typeof(Program).Module);
result.DefineParameter(1, ParameterAttributes.None, "__result");
ILGenerator il = result.GetILGenerator();
Type type = typeof(OriginalCode<T>);
PropertyInfo propertyInfo = type.GetProperty("Value");
// create a reference to the Value Property
PropertyInfo ValueProperty = typeof(OriginalCode<T>).GetProperty("Value");
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, Value);
il.Emit(OpCodes.Stind_Ref);
il.Emit(OpCodes.Ret);
return result;
}
}
so this is how I would use it:
string testRefStr = "Test";
var originalCodeInstance = new OriginalCode<string>("New Test");
var newStringDelegate = (OriginalCode<string>.PostFix)originalCodeInstance.Postfix().CreateDelegate(typeof(OriginalCode<string>.PostFix));
newStringDelegate(ref testRefStr);
int testRefInt = 55;
var originalCodeInstance = new OriginalCode<int>(75);
var newIntDelegate = (OriginalCode<int>.PostFix)originalCodeInstance.Postfix().CreateDelegate(typeof(OriginalCode<int>.PostFix));
newIntDelegate(ref testRefInt);
this currently only works if T is a string, but I need it to work on all types incuding reference and primitive types and Tasks/Interfaces and other abstract types.
How would i go about implementing this? im not very good at Opcodes and IL its outside of my knowledge - im really only working with it for this part, im so close but I'm quite stuck. Thanks All
I know the reason for the failiure with other types is that Opcodes.Ldstr only loads a string - I have also tried OpCodes.Ldobj but it didn't work for me - since i can't debug OpCodes in a DynamicMethod i always get unhelpful outputs such as Invalid Code detected.
I have attempted using OpCodes.Callvirt but that also didn't work for a similar reason to above
I have tried to get the method definition of the Getter of the Value property and trying to use Opcodes.Call - this didn't work either.
If you think these Opcodes should work please remember im not familiar with Opcodes and more-than-likely didn't properly use it haha - please tell me how to properly use the Opcodes.
Thanks All
After discussion, it seems that the underlying requirement here is to set an arg to an arbitrary value, from (for some reason) a delegate to a static method. Now, the problem here is that the types you can write directly in IL are very limited - integers, strings, floating-point, nulls, etc. If you only need to work with a few very specific types, then you can special-case each, but in the general case: that just doesn't work. As such, the typical workaround is to use ref-emit to declare a dynamic type, with a static field where we can shove the value, and then essentially use (as our method body):
This requires a lot more work than
DynamicMethod, as you need anAssemblyBuilder,ModuleBuilder,TypeBuilderandMethodBuilderetc. But: it should work: