如何通过反射在setter中调用方法
本文关键字:调用 方法 setter 何通过 反射 | 更新日期: 2023-09-27 18:18:36
我正在动态创建一个继承MvvmLight的ViewModelBase的类。在类中属性应该实现INotifyPropertyChanged接口方法RaiseEvent。
这是完整的代码// Our intermediate language generator
ILGenerator ilgen;
// The assembly builder
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("PeopleLibrary"), AssemblyBuilderAccess.RunAndSave);
// The module builder
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("PeopleLibrary", "PeopleLibrary.dll");
// The person class builder
TypeBuilder personBuilder = modBuilder.DefineType("PeopleLibrary.Person", TypeAttributes.Class | TypeAttributes.Public, typeof(ViewModelBase));
// The default constructor
ConstructorBuilder ctorBuilder = personBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Two fields: m_firstname, m_lastname
FieldBuilder fBuilderFirstName = personBuilder.DefineField("firstname", typeof(string), FieldAttributes.Private);
FieldBuilder fBuilderLastName = personBuilder.DefineField("lastname", typeof(string), FieldAttributes.Private);
// Two properties for this object: FirstName, LastName
PropertyBuilder pBuilderFirstName = personBuilder.DefineProperty("FirstName", System.Reflection.PropertyAttributes.HasDefault, typeof(string), null);
PropertyBuilder pBuilderLastName = personBuilder.DefineProperty("LastName", System.Reflection.PropertyAttributes.HasDefault, typeof(string), null);
// Custom attributes for get, set accessors
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
// get,set accessors for FirstName
MethodBuilder mGetFirstNameBuilder = personBuilder.DefineMethod("get_FirstName", getSetAttr, typeof(string), Type.EmptyTypes);
// Code generation
ilgen = mGetFirstNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, fBuilderFirstName); // returning the firstname field
ilgen.Emit(OpCodes.Ret);
MethodBuilder mSetFirstNameBuilder = personBuilder.DefineMethod("set_FirstName", getSetAttr, null, new Type[] { typeof(string) });
// Code generation
ilgen = mSetFirstNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Stfld, fBuilderFirstName); // setting the firstname field from the first argument (1)
ilgen.Emit(OpCodes.Ret);
// get,set accessors for LastName
MethodBuilder mGetLastNameBuilder = personBuilder.DefineMethod("get_LastName", getSetAttr, typeof(string), Type.EmptyTypes);
// Code generation
ilgen = mGetLastNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, fBuilderLastName); // returning the firstname field
ilgen.Emit(OpCodes.Ret);
MethodBuilder mSetLastNameBuilder = personBuilder.DefineMethod("set_LastName", getSetAttr, null, new Type[] { typeof(string) });
// Code generation
ilgen = mSetLastNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Stfld, fBuilderLastName); // setting the firstname field from the first argument (1)
ilgen.Emit(OpCodes.Ret);
// Assigning get/set accessors
pBuilderFirstName.SetGetMethod(mGetFirstNameBuilder);
pBuilderFirstName.SetSetMethod(mSetFirstNameBuilder);
pBuilderLastName.SetGetMethod(mGetLastNameBuilder);
pBuilderLastName.SetSetMethod(mSetLastNameBuilder);
// Now, a custom method named GetFullName that concatenates FirstName and LastName properties
MethodBuilder mGetFullNameBuilder = personBuilder.DefineMethod("GetFullName", MethodAttributes.Public, typeof(string), Type.EmptyTypes);
// Code generation
ilgen = mGetFullNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, mGetFirstNameBuilder); // getting the firstname
ilgen.Emit(OpCodes.Ldstr, " "); // an space
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, mGetLastNameBuilder); // getting the lastname
// We need the 'Concat' method from string type
MethodInfo concatMethod = typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) });
ilgen.Emit(OpCodes.Call, concatMethod); // calling concat and returning the result
ilgen.Emit(OpCodes.Ret);
// Another constructor that initializes firstname and lastname
ConstructorBuilder ctorBuilder2 = personBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(string), typeof(string) });
ctorBuilder2.DefineParameter(1, ParameterAttributes.None, "firstname");
ctorBuilder2.DefineParameter(2, ParameterAttributes.None, "lastname");
// Code generation
ilgen = ctorBuilder2.GetILGenerator();
// First of all, we need to call the base constructor,
// the Object's constructor in this sample
Type objType = Type.GetType("System.Object");
ConstructorInfo objCtor = objType.GetConstructor(Type.EmptyTypes);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, objCtor); // calling the Object's constructor
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, mSetFirstNameBuilder); // setting the firstname field from the first argument (1)
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_2);
ilgen.Emit(OpCodes.Call, mSetLastNameBuilder); // setting the lastname field from the second argument (2)
ilgen.Emit(OpCodes.Ret);
// Finally, create the type and save the assembly
var type = personBuilder.CreateType();
asmBuilder.Save("PeopleLibrary.dll");
在setter中创建属性时我需要这样做
public string StudentName
{
get
{
return this.studentName;
}
set
{
this.Set(() => this.StudentName, ref this.studentName, value);
}
}
但是现在,根据代码样本,我发现它在反射中是这样的。
private string firstname;
public string FirstName
{
get
{
return this.firstname;
}
set
{
this.firstname = obj0;
}
}
我的要求是我需要调用setter中的基类方法Set,如所示。我修改了代码并在反射中继承了基类。但是我不能设置setter。
请帮帮我。
对于此类问题有一个小技巧。下载这个插件
我刚刚编译了下面这个小示例: private string studentName;
public string StudentName
{
get { return this.studentName; }
set { this.Set(() => this.StudentName, ref this.studentName, value); }
}
private void Set(Func<string> func, ref string s, string value)
{
}
用Reflection.Emit
语言查看Reflector
中的属性设置器:
public MethodBuilder BuildMethodset_StudentName(TypeBuilder type)
{
// Declaring method builder
MethodBuilder method = type.DefineMethod("set_StudentName");
// Preparing Reflection instances
MethodInfo method1 = typeof(Program).GetMethod(
"<set_StudentName>b__0",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
},
null
);
ConstructorInfo ctor2 = typeof(System.Func<>).MakeGenericType(typeof(String)).GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
typeof(Object),
typeof(IntPtr)
},
null
);
FieldInfo field3 = typeof(Program).GetField("studentName", BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo method4 = typeof(Program).GetMethod(
"Set",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
typeof(System.Func<>).MakeGenericType(typeof(String)),
typeof(String&),
typeof(String)
},
null
);
// Method attributes
method.Attributes =
System.Reflection.MethodAttributes.Public
| System.Reflection.MethodAttributes.HideBySig;
// Setting return type
method.SetReturnType(typeof(Void));
// Adding parameters
method.SetParameters(
typeof(String)
);
// Parameter value
ParameterBuilder value = method.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator gen = method.GetILGenerator();
// Writing body
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldftn,method1);
gen.Emit(OpCodes.Newobj,ctor2);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldflda,field3);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call,method4);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ret);
// finished
return method;
}
<set_StudentName>b__0
方法是为setter中的lambda生成的方法,看起来像这样:
[CompilerGenerated]
private string <set_StudentName>b__0()
{
return this.StudentName;
}