Pergunta

No meu aplicativo, preciso criar dinamicamente um tipo que contém várias propriedades. Estou ciente de que, em casos como esse, é preciso gerar um CIL para métodos Getter e Setter de uma propriedade usando um Ilgenerator.

Mais por uma tentativa e erro do que qualquer outra coisa, finalmente cheguei ao código a seguir que gera um método de setter para mim:

MethodBuilder setMethod = customTypeBuilder.DefineMethod(propertyName + "_set", MethodAttributes.Public | MethodAttributes.HideBySig, null, new Type[] {propertyType});
ILGenerator setIlGenerator = setMethod.GetILGenerator();
setIlGenerator.Emit(OpCodes.Ldarg_0);
setIlGenerator.Emit(OpCodes.Ldarg_1);
setIlGenerator.Emit(OpCodes.Stfld, backingField);
setIlGenerator.Emit(OpCodes.Ret);

O código funciona bem o suficiente, mas há uma coisa que não entendo sobre isso. Por que é necessário chamar a instrução 'LDARG_0'?

Sei que se refere ao primeiro argumento implícito do método, a referência "essa", portanto, o valor real para o setter é armazenado no segundo argumento. Eu pensei que deveria ser suficiente ligar apenas para a instrução LDARG_1, o que levaria o segundo argumento para a pilha (no final, no setter, não preciso examinar a referência "essa", para que eu não precise faça qualquer coisa com isso), mas isso resulta na parte do TargetInvocationException quando tento definir o valor da propriedade.

Obrigada!

Foi útil?

Solução

Se você não empurre o valor "esse" para a pilha, como iria Stfld Sabe o campo de qual objeto mudar? Você pode estar tentando escrever um setter como este:

public int Bizarre
{
    set { otherObject.Field = value; }
}

Basicamente, Stfld é documentado precisar de dois valores na pilha: um para o "alvo" do novo valor e um para o próprio valor. É certo que o diagrama de transição da pilha na ECMA 335 é mais claro:

…, obj, value => …,

Em outras palavras: "O STFLD exibirá os dois primeiros elementos da pilha".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top