如何在C#EMIT中使用不确定参数创建动态函数

发布于 2025-01-24 08:31:20 字数 4313 浏览 5 评论 0原文

我想在项目中创建动态函数,但是函数参数的数量不确定,也许是两个,也许是三个或更多,然后我想在项目中运行静态函数,静态函数接受某些参数,因此,我该怎么做?最重要的是如何处理参数?

我的动态函数演示

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);
            }

我的静态函数结构,只有 paramlist 需要在运行时创建,其他人可以

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

在两天后 通过 udfcreate 获得 非常感谢@jeremylakeman,非常有帮助

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);
        }

。 il.emit(opcodes.call,“ getapiresult”); 。我已经尝试过,但是我不知道该如何处理,您能帮上解决这个问题吗? My goal is seems like thissample

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

破晓 2025-01-31 08:31:20

简化了您的示例(从注释),您想生成类似的方法;

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

我没有使用il.emit的实际经验,但是我建议您首先尝试准确输出该方法。然后将数组创建变成循环。修改上面具有注释的行,以相似的ldc.i4/ldarg op代码,允许您指定显式int或参数值值。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文