0

I want to create dynamic function in my project, but the number of function parameters is not sure,maybe two,maybe three or more,and then i want to run a static function already in the project,the static function accept some parameters,so,how could i do it with emit? and the most important is how to deal the parameters?

My dynamic function demo

public static void UDFCreate(string name, string type,List<string> paramList, string APIID)
{
            Type[] types = new Type[paramList.Count];
            foreach (string param in paramList)
            {
                int index = paramList.IndexOf(param);
                types[index] = typeof(double);
            }
            
            DynamicMethod mult = new DynamicMethod(name, typeof(double), types, typeof(UDFGenerator));
            ILGenerator il = mult.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);//
            il.Emit(OpCodes.Ldarg_1);// 
            il.Emit(OpCodes.Add);// 
            il.Emit(OpCodes.Ret);// 
            List<Delegate> delegates = new List<Delegate>();
            delegates.Add(mult.CreateDelegate(typeof(Func<double, double, double>)));
            // 
            ExcelFunctionAttribute att = new ExcelFunctionAttribute();
            att.Name = name;
            att.Description = "A function to multiply two numbers";
    
            List<object> funcAttribs = new List<object>();
            funcAttribs.Add(att);
            // 
            ExcelArgumentAttribute atta1 = new ExcelArgumentAttribute();
            atta1.Description = "is the first number";
    
            ExcelArgumentAttribute atta2 = new ExcelArgumentAttribute();
            atta2.Description = "is the second number";
            List<object> argAttribs = new List<object>();
            argAttribs.Add(atta1);
            argAttribs.Add(atta2);
    
            List<List<object>> argAttribsList = new List<List<object>>();
            argAttribsList.Add(argAttribs);
            try
            {
                // 
                ExcelIntegration.RegisterDelegates(delegates, funcAttribs, argAttribsList);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

My static function struct, only the paramList need create in runtime,others can get byUDFCreate

private static async void GetApiResult(string id, string type, List<string> paramNameList, params string[] paramList)

After two days later Thanks @JeremyLakeman very much,that really helpful.And then I coding like this

private static void EmitTwo(ILGenerator il, string type, List<string> paramList, string APIID)
        {
            // Stores the APIID in a local variable with index 0
            il.Emit(OpCodes.Ldarg_0); // this line is must
            il.Emit(OpCodes.Ldfld, APIID);
            il.Emit(OpCodes.Stloc_0);
            // Stores the type in a local variable with index 1
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, type);
            il.Emit(OpCodes.Stloc_1);
            // Create an array of the same size as the paramList
            il.Emit(OpCodes.Ldc_I4, paramList.Count);
            il.Emit(OpCodes.Newarr, typeof(object));
            foreach (var param in paramList)
            {
                int index = paramList.IndexOf(param);
                // Replaces the value of the array with an input parameter, subscript should starts at 1
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldc_I4, index);
                il.Emit(OpCodes.Ldarg_S, index + 1);
                il.Emit(OpCodes.Stelem_Ref);
            }
            il.Emit(OpCodes.Stloc_2);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Ldloc_2);
            il.Emit(OpCodes.Call, "GetApiResult");
            il.Emit(OpCodes.Ldstr, "LOADING");
            il.Emit(OpCodes.Ret);
        }

But it cant work fine,i got the errors in il.Emit(OpCodes.Ldfld, APIID);and in il.Emit(OpCodes.Call, "GetApiResult");.I have tried, but i dont known how to deal that,could you help to fix that? My goal is seems like thissample

7
  • So instead of Ldarg_0 you want Ldarg ? learn.microsoft.com/en-us/dotnet/api/… Commented Apr 27, 2022 at 5:48
  • @JeremyLakeman And then?if i emit Ldarg,how could i run the static function? Commented Apr 27, 2022 at 6:01
  • Maybe you should start with a disassembled example of what you are trying to achieve. eg sharplab.io/… Commented Apr 27, 2022 at 6:24
  • @JeremyLakeman Thank you very much,and i need your help again,please Commented Apr 28, 2022 at 11:51
  • learn.microsoft.com/en-us/dotnet/api/… "The object's field is specified by a metadata token that must refer to a field member. " You need to locate the FieldInfo for the field somehow. While you've posted your attempt a calling .Emit you haven't really explained what you are trying to achieve. Try including an example C# method with the behaviour you are trying to achieve. Commented Apr 28, 2022 at 14:07

1 Answer 1

0

Simplifying your example (from comments), you want to generate a method like;

public string test(Object a, Object b){
    print("name","type",new object[]{
        a,
        b
    });
    return "LOADING";
}

Which would result in IL similar to;

IL_0000: ldarg.0
IL_0001: ldstr "name"
IL_0006: ldstr "type"
IL_000b: ldc.i4.2 // array size
IL_000c: newarr [System.Runtime]System.Object
IL_0011: dup
IL_0012: ldc.i4.0 // array index 0
IL_0013: ldarg.1  // argument value
IL_0014: stelem.ref
IL_0015: dup
IL_0016: ldc.i4.1 // array index 1
IL_0017: ldarg.2  // argument value
IL_0018: stelem.ref
IL_0019: call instance void C::print(string, string, object[])
IL_001e: ldstr "LOADING"
IL_0023: ret

I don't have any actual experience with using il.Emit, but I would suggest you start by trying to output that method exactly. Then turn the array creation into a loop. Modifying the lines above which have comments, into the similar ldc.i4 / ldarg op codes which allow you to specify an explicit int or argument value.

Sign up to request clarification or add additional context in comments.

2 Comments

il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, APIID); il.Emit(OpCodes.Ldstr, type); il.Emit(OpCodes.Ldc_I4, paramList.Count); il.Emit(OpCodes.Newarr, typeof(object)); foreach (var param in paramList) { int index = paramList.IndexOf(param); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Ldarg_S, index +1); il.Emit(OpCodes.Stelem_Ref); } MethodInfo mi = typeof(UDFGenerator).GetMethod("GetApiResult", BindingFlags.NonPublic | BindingFlags.Static); il.Emit(OpCodes.Call, mi); il.Emit(OpCodes.Ldstr, "LOADING"); il.Emit(OpCodes.Ret);
This is my Emit code and it worked in TypeBuilder.DefineMethod but not DynamicMethod

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.