Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# IL使用Reflection.Emit调用带有params object[]参数的方法_C#_Cil_Reflection.emit - Fatal编程技术网

C# IL使用Reflection.Emit调用带有params object[]参数的方法

C# IL使用Reflection.Emit调用带有params object[]参数的方法,c#,cil,reflection.emit,C#,Cil,Reflection.emit,我正在编写一个库,它需要稍后的类型构建。库使用平台.NETCore2.0 我使用Reflection.Emit生成的某些类型存在问题 public class GeneratedA : A, IA { public void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4, params object[] otherArgs) { DoClass(a

我正在编写一个库,它需要稍后的类型构建。库使用平台.NETCore2.0

我使用Reflection.Emit生成的某些类型存在问题

public class GeneratedA : A, IA
{
    public void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4, params object[] otherArgs)
    {
        DoClass(arg0, arg1, arg2, arg3, arg4, otherArgs);
    }
}
公共类生成A:A,IA
{
public void DoInterface(字符串arg0、布尔arg1、整数arg2、对象arg3、列表arg4、参数对象[]其他args)
{
docclass(arg0、arg1、arg2、arg3、arg4、其他args);
}
}
对于这些类型:

public interface IA
{
    void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4,  params object[] otherArgs);
}
public class A
{
    public void DoClass(params object[] args)
    {
    }
}
公共接口IA
{
void DoInterface(字符串arg0、bool arg1、int arg2、对象arg3、列表arg4、参数对象[]其他args);
}
公共A类
{
公共void DoClass(参数对象[]args)
{
}
}
示例IL代码:

class Program
{
    public static class Generator
    {
        public static T Create<T>()
            where T : class
        {
            AssemblyName aName = new AssemblyName("DynamicAssembly");
            AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
            ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);

            var interfaceType = typeof(T);
            var interfaceMethod = interfaceType.GetMethod("DoInterface");
            var interfaceMethodArgs = interfaceMethod.GetParameters().Select(x => x.ParameterType).ToArray();
            var classType = typeof(A);
            var classMethod = classType.GetMethod("DoClass");
            var returnType = typeof(void);
            var baseType = typeof(object);
            var baseConstructor = baseType.GetConstructor(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance, null, Type.EmptyTypes, null);


            TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, baseType);


            ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
            ILGenerator ctorIL = ctor.GetILGenerator();
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Call, baseConstructor);
            ctorIL.Emit(OpCodes.Nop);
            ctorIL.Emit(OpCodes.Nop);
            ctorIL.Emit(OpCodes.Ret);


            tb.AddInterfaceImplementation(interfaceType);

            MethodBuilder mbIM = tb.DefineMethod(interfaceType.Name + "." + interfaceMethod.Name,
                MethodAttributes.Private | MethodAttributes.HideBySig |
                MethodAttributes.NewSlot | MethodAttributes.Virtual |
                MethodAttributes.Final,
                returnType,
                interfaceMethodArgs);
            ILGenerator genIM = mbIM.GetILGenerator();
            // ToDo
            genIM.Emit(OpCodes.Call, classMethod);
            genIM.Emit(OpCodes.Ret);


            tb.DefineMethodOverride(mbIM, interfaceMethod);

            Type t = tb.CreateType();

            return Activator.CreateInstance(t) as T;
        }

    }

    static void Main(string[] args)
    {
        IA a;
        a = new GeneratedA();
        a.DoInterface("0", true, 2, 3, new List<float>() { 4 }, "5", 6);
        a = Generator.Create<IA>();
        a.DoInterface("0", true, 2, 3, new List<float>() { 4 }, "5", 6);
    }
}
类程序
{
公共静态类生成器
{
publicstatict-Create()
T:在哪里上课
{
AssemblyName aName=新的AssemblyName(“DynamicAssembly”);
AssemblyBuilder ab=AssemblyBuilder.DefinedDynamicAssembly(新的AssemblyName(Guid.NewGuid().ToString()),AssemblyBuilderAccess.Run);
ModuleBuilder mb=ab.definedDynamicModule(aName.Name);
var interfaceType=类型(T);
var interfaceMethod=interfaceType.GetMethod(“DoInterface”);
var interfaceMethodArgs=interfaceMethod.GetParameters().Select(x=>x.ParameterType.ToArray();
var classType=类型(A);
var classMethod=classType.GetMethod(“DoClass”);
var returnType=类型(无效);
var baseType=类型(对象);
var baseConstructor=baseType.GetConstructor(BindingFlags.Public | BindingFlags.flattHierarchy | BindingFlags.Instance,null,Type.EmptyTypes,null);
TypeBuilder tb=mb.DefineType(“GeneratedA”,TypeAttributes.Public,baseType);
ConstructorBuilder ctor=tb.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,Type.EmptyTypes);
ILGenerator ctorIL=ctor.GetILGenerator();
ctorIL.Emit(操作码.Ldarg_0);
actoril.Emit(操作码.Call,baseConstructor);
发射(操作码Nop);
发射(操作码Nop);
ctorIL.Emit(操作码.Ret);
tb.AddInterfaceImplementation(interfaceType);
MethodBuilder mbIM=tb.DefineMethod(interfaceType.Name+“”+interfaceMethod.Name,
MethodAttributes.Private | MethodAttributes.hidebysing|
MethodAttributes.NewSlot | MethodAttributes.Virtual|
最后,
返回类型,
接口方法);
ILGenerator genIM=mbIM.GetILGenerator();
//待办事项
genIM.Emit(操作码.Call,类方法);
genIM.Emit(操作码Ret);
tb.定义方法(mbIM,接口方法);
类型t=tb.CreateType();
将Activator.CreateInstance(t)返回为t;
}
}
静态void Main(字符串[]参数)
{
IA a;
a=新一代a();
a、 DoInterface(“0”,true,2,3,new List(){4},“5”,6);
a=生成器.Create();
a、 DoInterface(“0”,true,2,3,new List(){4},“5”,6);
}
}
每当我试图填写注释“ToDo”时,就会出现一个错误“公共语言运行库检测到一个无效程序”

我请求帮助调用方法DoClass


感谢调用
DoClass
方法您需要提供参数,只是
调用classMethod
不起作用

第一个参数当然是“this”引用:

genIM.Emit(OpCodes.Ldarg_0);
第二个参数是对象数组
params
是编译器的特性,如果您自己构建代码,您必须将其视为
params
不存在。我的意思是-当

 DoClass();
用代码编写时是合法的-编译如下:

DoClass(new object[0]);
所以,当您发出这个调用时,您应该始终提供array of objects参数,不能忽略它

要将对象数组推送到堆栈,请执行以下操作:

// push array length (0, for example) to stack
genIM.Emit(OpCodes.Ldc_I4_0); 
// push new array with length given by the above value (0)
genIM.Emit(OpCodes.Newarr, typeof(object)); 
此时,您的代码将编译并运行良好。这类似于:

public class GeneratedA : A, IA
{
    public void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4, params object[] otherArgs)
    {
        DoClass();
    }
}
要传递第二个参数:

genIM.Emit(OpCodes.Dup);
// push index to store next element at (1)
genIM.Emit(OpCodes.Ldc_I4_1);
// push arg2
genIM.Emit(OpCodes.Ldarg_2);
// box, because boolean is value type, and you store it in object array
genIM.Emit(OpCodes.Box, typeof(bool));
// store in array (yourArguments[1] = (object) arg2
genIM.Emit(OpCodes.Stelem_Ref);
等等

将参数推入数组时,不要忘记更改其长度以反映参数的数量:

// push array length - 6
genIM.Emit(OpCodes.Ldc_I4_6); 
// push new array with length given by the above value (6)
genIM.Emit(OpCodes.Newarr, typeof(object)); 
还请注意,您可能需要更改:

TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, baseType);

或者只需更改为
baseType=typeof(A)
,因为您希望从
A
继承生成的类,而不是从
对象继承生成的类

使用前2个参数发出调用的完整代码:

ILGenerator genIM = mbIM.GetILGenerator();            
genIM.Emit(OpCodes.Ldarg_0);   
genIM.Emit(OpCodes.Ldc_I4_2);
genIM.Emit(OpCodes.Newarr, typeof(object));

genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_0);
genIM.Emit(OpCodes.Ldarg_1);
genIM.Emit(OpCodes.Stelem_Ref);

genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_1);
genIM.Emit(OpCodes.Ldarg_2);
genIM.Emit(OpCodes.Box, typeof(bool));
genIM.Emit(OpCodes.Stelem_Ref);

genIM.Emit(OpCodes.Call, classMethod);
genIM.Emit(OpCodes.Ret);
TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, classType);
ILGenerator genIM = mbIM.GetILGenerator();            
genIM.Emit(OpCodes.Ldarg_0);   
genIM.Emit(OpCodes.Ldc_I4_2);
genIM.Emit(OpCodes.Newarr, typeof(object));

genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_0);
genIM.Emit(OpCodes.Ldarg_1);
genIM.Emit(OpCodes.Stelem_Ref);

genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_1);
genIM.Emit(OpCodes.Ldarg_2);
genIM.Emit(OpCodes.Box, typeof(bool));
genIM.Emit(OpCodes.Stelem_Ref);

genIM.Emit(OpCodes.Call, classMethod);
genIM.Emit(OpCodes.Ret);