Hej All
I have some code that builds a new TYPE runtime, it sets the GET and SET method using MethodBuilder. (Its an exampel from the web, and thanks to the Guy, that wrote it, i unfortantly lost the ref. to him, but he is in my thoughts)
TypeBuilder typeBuilder = module.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class);
I add a method to the class this way.
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);
It works fine, i would however like to change the setmethod to something more complex, so i write this test code.
public class Customer
{
private string _name;
public string name
{
get { return _name; }
set {
if ( string.IsNullOrEmpty( value ) )
{
throw new ValidationException("Please set a value");
}
_name = value;
}
}
public string lastname { get; set; }
}
Compile and then use Reflector to get the 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
}
So the task is to implement it into the SET EMIT code.
// 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);
This, is where i come short, i cant get it to work. It seams that i can's "just" copy the code over, and my MSIL skills are limited. hereunder is my error.
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)
On the 3 line, these red underlines give thede errors…
- Bool = ") Expetced"
- [mscorlib]System = "; expected"
- :: = ". expected"
- and the last ) gives "invalid
expression term string"
I wonder why i cant use reflector, the code should be ok? or?
The solution it to find a program / Method that displays MSIL code that can be used in the EMIT statement.
This is just an example so the code will change, so it's not a solution to answer the correct code (allthou it will be nice to get the example working) but a more permenent "way" of getting the correct MSIL from C#.
Peww, a long question, i hope i have everything in here.
Regards
ReLoad
Best Answer
You need to get the
MethodInfo
- in this case:Actually, though, I'd be looking into
Expression
for this - I believe there is aCompile
for silverlightExpression
, and you don't have to learn IL!Note that if there are multiple overloads you generally have to do a lot more work to get the
MethodInfo
(it just happens thatstring.IsNullOrEmpty
is easy to use). Also, note that "instance" methods should useOpCodes.Callvirt
; static methods (like this one) should useOpCodes.Call
.