Прежде всего, у меня есть класс
internal class Parent
{
protected void Write(string message, [CallerMemberName] string caller = null)
{
Console.WriteLine($"{caller} :: {message}");
}
}
, и я хочу динамически создать класс, у класса есть свойство «Имя», если значение свойства изменилось, то вызов метода write выглядит так
class Child : Parent
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
Write("changedto: " + value);
_name = value;
}
}
}
}
, что я хочу знать, это предложение выделения.как написать это в Emit.пожалуйста, помогите.
Я хочу код ниже
private static MethodBuilder BuildSetter(TypeBuilder typeBuilder, PropertyInfo property, FieldBuilder fieldBuilder, MethodAttributes attributes)
{
var setterBuilder = typeBuilder.DefineMethod($"set_{property.Name}", attributes, null, new Type[] { property.PropertyType });
var ilGenerator = setterBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0); //this
ilGenerator.Emit(OpCodes.Ldarg_1); // the first one in arguments list
//code should be here
ilGenerator.Emit(OpCodes.Stfld, fieldBuilder);
ilGenerator.Emit(OpCodes.Ret);
return setterBuilder;
}
Обновлен
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public,typeof(PropertyChanged));
var t = typeof(PropertyChanged);
var m2 = t.GetMethod("ValueChanged");
Вы видите, когда ясоздать тип, я использую родительский тип, а в родительском типе есть метод с именем «ValueChanged»
protected void ValueChanged(object value,[CallerMemberName] string property = null)
я хочу вызвать его в методе set.
обновление 2
private static MethodBuilder BuildSetter(TypeBuilder typeBuilder, PropertyInfo property, FieldBuilder fieldBuilder, MethodAttributes attributes)
{
var propertyType = property.PropertyType;
var setterBuilder = typeBuilder.DefineMethod($"set_{property.Name}", attributes, null, new Type[] { propertyType });
var setIl = setterBuilder.GetILGenerator();
Label exitSet = setIl.DefineLabel(); // define label to jump in case condition is false
setIl.Emit(OpCodes.Ldarg_0); // this
setIl.Emit(OpCodes.Ldfld, fieldBuilder); // _name field
setIl.Emit(OpCodes.Ldarg_1); // value
var inequality = propertyType.GetMethod("Equals", new[] { propertyType});
setIl.Emit(OpCodes.Callvirt, inequality); // '!=' method
setIl.Emit(OpCodes.Brtrue_S, exitSet); // check for inequality
setIl.Emit(OpCodes.Ldarg_0); // load string literal
setIl.Emit(OpCodes.Ldarg_1); // value
setIl.Emit(OpCodes.Ldstr, property.Name);
var m = typeBuilder.BaseType.GetMethod("ValueChanged", new Type[] {typeof(object),typeof(string) });
setIl.Emit(OpCodes.Call, m);
setIl.Emit(OpCodes.Ldarg_0); // this
setIl.Emit(OpCodes.Ldarg_1); // value
setIl.Emit(OpCodes.Stfld, fieldBuilder); // save the new value into _name
setIl.MarkLabel(exitSet); // mark the label
setIl.Emit(OpCodes.Ret); // return
return setterBuilder;
}
обновление 3 снимки экрана
обновление 4
возможно, я нашел причину ошибки, см. ОтражениеНаследование типа и типа: вызов конструкторов базового типа
обновление 5
наконец, я получил причину ошибки.это было не то, о чем я догадывался в обновлении 4, это было вызвано вызовом родительского метода "ValueChanged".прежде чем передать параметр в метод, мы должны Box его как Object, если исходный тип данных IsValueType .см. ссылку ниже,
C # эмитт, тип сравнения значения