C#, Reflection.Emit старается изо всех сил

Я хотел попробовать, как работает System.Reflection.Emit, но в итоге столкнулся с проблемой. Я хотел создать (используя Emit) какой-нибудь простой класс, например:

using System;

namespace emit
{
    class Builder
    {
        private String name;

        public Builder(String builderName)
        {
            name = builderName;
        }

        public override int GetHashCode()
        {
            return name.GetHashCode();
        }

        public override string ToString()
        {
            return this.name;
        }
    }
}

Я прошел несколько руководств, и мне удалось создать динамическую библиотеку. Я сохранил эту библиотеку на своем диске, а затем загрузил ее с помощью отражения. Я смог отфильтровать его типы, конструкторы и методы. Я также успешно вызвал конструктор, передав желаемый string. Тем не менее, есть проблема, когда я пытаюсь вызвать любой из методов - выдается System.Reflection.TargetInvocationException.

Вот как я реализовал GetHashCode():

MethodBuilder mHashCode = tBuilder.DefineMethod("GetHashCode",
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
                CallingConventions.HasThis, typeof(System.Int32), null);
            mHashCode.SetImplementationFlags(MethodImplAttributes.Managed);
            ILGenerator mHashGenerator = mHashCode.GetILGenerator();

            MethodInfo defaultHashCode = typeof(object).GetMethod("GetHashCode");

            mHashGenerator.Emit(OpCodes.Ldfld, simpleName);
            mHashGenerator.Emit(OpCodes.Callvirt, defaultHashCode);
            mHashGenerator.Emit(OpCodes.Ret);

tBuilder — это TypeBuilder, который я создаю.

После сохранения сборки и просмотра с помощью ILDSASM это выглядит так: введите здесь описание изображения

И EditModule.dll: введите здесь описание изображения

К сожалению, этот метод не вызывается. Вот код:

                Type dType = asm.GetTypes()[0];
                ConstructorInfo dConstructor = dType.GetConstructor(new Type[] { typeof(string) });
                object dObject = dConstructor.Invoke(new object[] { "Pawel" });
                MethodInfo[] dMethods = dType.GetMethods();
                foreach(var mi in dMethods)
                {
                    Console.WriteLine(mi.Name);
                }
                //method with `0` index is `GetHashCode()`
                dMethods[0].Invoke(dObject, null);

Кто-нибудь знает, что я могу делать неправильно?


person Paweł Poręba    schedule 12.01.2016    source источник
comment
Каково внутреннее исключение TargetInvocationException?   -  person stuartd    schedule 12.01.2016
comment
Это что-то вроде CLR Environment has captured inappropriate program. StackTrace показывает, что причиной этого является BuilderEmitType.GetHashCode().   -  person Paweł Poręba    schedule 12.01.2016


Ответы (1)


Этот фрагмент

mHashGenerator.Emit(OpCodes.Ldfld, simpleName);

пытается получить значение поля, но вы забыли, что для этого ему нужен экземпляр. Поскольку метод, который вы создаете, является методом экземпляра, this является скрытым первым аргументом метода, поэтому, чтобы получить значение this.name, вы должны использовать следующее

mHashGenerator.Emit(OpCodes.Ldarg_0);
mHashGenerator.Emit(OpCodes.Ldfld, simpleName);
person Ivan Stoev    schedule 12.01.2016
comment
Вот так! Спасибо, я неправильно понял значение перечисления CallingConvention. - person Paweł Poręba; 12.01.2016