Silverlight 3.0 C # - Использование Methodbuilder для создания метода SET и добавление MSIL с помощью ILGenerator и Emit - PullRequest
2 голосов
/ 15 января 2010

Hej All

У меня есть некоторый код, который создает новую среду выполнения TYPE, он устанавливает метод GET и SET с использованием MethodBuilder. (Это отрывок из Интернета, и благодаря парню, который написал это, я, к сожалению, потерял ссылку на него, но он в моих мыслях)

TypeBuilder typeBuilder = module.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class);

Я добавляю метод в класс таким образом.

    MethodAttributes GetSetAttr =
      MethodAttributes.Public |
      MethodAttributes.HideBySig;

// Define the "get" accessor method for current private field.
                MethodBuilder currGetPropMthdBldr =
                    typeBuilder.DefineMethod("get_value",
                                               GetSetAttr,
                                               typeof(string),
                                               Type.EmptyTypes);

                // Intermediate Language stuff...
                ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
                currGetIL.Emit(OpCodes.Ldarg_0);
                currGetIL.Emit(OpCodes.Ldfld, field);
                currGetIL.Emit(OpCodes.Ret);

                // Define the "set" accessor method for current private field.
                MethodBuilder currSetPropMthdBldr =
                    typeBuilder.DefineMethod("set_value",
                                               GetSetAttr,
                                               null,
                                               new Type[] { typeof(string) });

                // Again some Intermediate Language stuff...
                ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                currSetIL.Emit(OpCodes.Ldarg_0);
                currSetIL.Emit(OpCodes.Ldarg_1);
                currSetIL.Emit(OpCodes.Stfld, field);
                currSetIL.Emit(OpCodes.Ret);



                // Last, we must map the two methods created above to our PropertyBuilder to 
                // their corresponding behaviors, "get" and "set" respectively. 
                property.SetGetMethod(currGetPropMthdBldr);
                property.SetSetMethod(currSetPropMthdBldr);

Он работает нормально, однако я хотел бы изменить setmethod на что-то более сложное, поэтому я пишу этот тестовый код.

Заказчик публичного класса { приватная строка _name; публичное имя строки { get {return _name; } задавать { if (string.IsNullOrEmpty (value)) { бросить новое ValidationException («Пожалуйста, установите значение»); } _name = значение; } } публичная строка lastname {get; задавать; } }

Скомпилируйте, а затем используйте Reflector для получения MSIL.

.method public hidebysig specialname instance void set_name(string 'value') cil managed
{
    .maxstack 2
    .locals init (
        [0] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: call bool [mscorlib]System.String::IsNullOrEmpty(string)
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: brtrue.s L_001a
    L_000e: nop 
    L_000f: ldstr "Please set a value"
    L_0014: newobj instance void [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationException::.ctor(string)
    L_0019: throw 
    L_001a: ldarg.0 
    L_001b: ldarg.1 
    L_001c: stfld string AnnotationTest.MainPage/Customer::_name
    L_0021: ret 
}

Таким образом, задача состоит в том, чтобы внедрить его в код SET EMIT.

                // Again some Intermediate Language stuff...
                ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                currSetIL.Emit(OpCodes.Ldarg_0);
                currSetIL.Emit(OpCodes.Ldarg_1);
                currSetIL.Emit(OpCodes.Stfld, field);
                currSetIL.Emit(OpCodes.Ret);

Это то место, где мне не хватает, я не могу заставить его работать. Кажется, что я могу просто скопировать код, и мои навыки работы с MSIL ограничены. в этом моя ошибка.

        currSetIL.Emit(OpCodes.Nop);  //       L_0000: nop 
        currSetIL.Emit(OpCodes.Ldarg_1);  //   L_0001: ldarg.1 
        currSetIL.Emit(OpCodes.Call bool [mscorlib]System.String::IsNullOrEmpty(string);// call bool [mscorlib]System.String::IsNullOrEmpty(string)

На 3-й строке эти красные подчеркивания показывают ошибки ...

  • Bool = ") Expetced"
  • [mscorlib] System = "; ожидается"
  • :: = ". Ожидается"
  • и последнее) дает "недействительным строка выражения "

Интересно, почему я не могу использовать рефлектор, код должен быть в порядке? или

Решение - найти программу / метод, отображающий код MSIL, который можно использовать в операторе EMIT.

Это всего лишь пример, поэтому код изменится, поэтому это не решение, чтобы ответить на правильный код (все, что будет хорошо, если пример будет работать), а более эффективный «способ» получить правильный MSIL из C # .

Пью, длинный вопрос, надеюсь, у меня здесь все есть.

С уважением Reload

1 Ответ

3 голосов
/ 15 января 2010

currSetIL.Emit (OpCodes.Call bool [mscorlib] System.String :: IsNullOrEmpty (string); // вызов bool [mscorlib] System.String :: IsNullOrEmpty (string)

Вам необходимо получить MethodInfo - в этом случае:

currSetIL.EmitCall(OpCodes.Call,typeof(string).GetMethod("IsNullOrEmpty"),null);

На самом деле, я бы посмотрел на Expression для этого - я считаю есть Compile для серебряного света Expression, и вам не нужно изучать IL!

Обратите внимание, что если есть несколько перегрузок, вам обычно нужно проделать гораздо больше работы, чтобы получить MethodInfo (просто так получается, что string.IsNullOrEmpty прост в использовании). Также обратите внимание, что методы «экземпляра» должны использовать OpCodes.Callvirt; статические методы (как этот) должны использовать OpCodes.Call.

...