Generating type at runtime
I need to create type with properties at runtime. Type must be look like this:
public class RunTimeType : BaseType
{
private string _field1;
public string Property1
{
get { return _field1; }
set
{
if (_field1 != value)
{
_field1 = value;
OnAfterPropertySet("Property1");
}
}
}
}
the question is how to create Set method 开发者_JAVA百科? Now i use folowing code :
var propertyName = "Property1";
var onAfterPropertySet = baseType.GetMethod("OnAfterPropertySet",
BindingFlags.Instance | BindingFlags.InvokeMethod |
BindingFlags.NonPublic, null, new[] { typeof(string) },
null);
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ldstr, propertyName);
currSetIL.Emit(OpCodes.Call, onAfterPropertySet);
currSetIL.Emit(OpCodes.Pop);
currSetIL.Emit(OpCodes.Ret);
but when i trying to set value to the property, exception is thrown
You're not really close. You forgot the equality test and passing the hidden this argument to the instance method. The best way to do this is to write the code in C# first:
class Test {
private string _field1;
private void OnAfterPropertySet(string arg) { }
public string Property1 {
set {
if (_field1 != value) {
_field1 = value;
OnAfterPropertySet("Property1");
}
}
}
}
Build it in the Release mode then take a look at the generated IL with ildasm.exe or Reflector:
IL_0000: ldarg.0
IL_0001: ldfld string ConsoleApplication1.Test::_field1
IL_0006: ldarg.1
IL_0007: call bool [mscorlib]System.String::op_Inequality(string,
string)
IL_000c: brfalse.s IL_0020
IL_000e: ldarg.0
IL_000f: ldarg.1
IL_0010: stfld string ConsoleApplication1.Test::_field1
IL_0015: ldarg.0
IL_0016: ldstr "Property1"
IL_001b: call instance void ConsoleApplication1.Test::OnAfterPropertySet(string)
IL_0020: ret
You need to Ldarg_0
before calling onAfterPropertySet
for the this
parameter.
精彩评论