我需要在运行时生成一个可以正常工作的类型。 但是,我还需要在生成的属性获取器中调用现有函数,以修改返回值。 这是生成属性的函数:
private PropertyBuilder CreateProperty(string propertyName,Type propertyType,MethodAttributes getterAttributes,MethodAttributes setterAttributes,bool isReadOnly,bool isWriteonly,TypeBuilder builder)
{
PropertyBuilder result = null;
if (builder != null && propertyType != null)
{
result = builder.DefineProperty(propertyName,PropertyAttributes.HasDefault,propertyType,null);
FieldBuilder fieldBuilder = builder.DefineField("_" + propertyName,FieldAttributes.Private);
if (!isWriteonly)
{
MethodBuilder getPropMthdBldr = builder.DefineMethod("get_" + propertyName,getterAttributes,Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld,fieldBuilder);
getIl.Emit(OpCodes.Ret);
result.SetGetMethod(getPropMthdBldr);
}
if (!isReadOnly)
{
MethodBuilder setPropMthdBldr = builder.DefineMethod("set_" + propertyName,setterAttributes,null,new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld,fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
result.SetSetMethod(setPropMthdBldr);
}
}
return result;
}
对我自己来说,一个完美的解决方案是,如果我可以将一个匿名方法传递给“ getProperty”,我将在getter中调用它。 (这是我的最终目标)。
但是我在getter内部的函数调用方面遇到了麻烦。 目前,我在静态类中使用静态函数作为调用。 我的创建属性函数当前如下所示:
private PropertyBuilder CreateProperty(string propertyName,TypeBuilder builder)
{
PropertyBuilder result = null;
if (builder != null && propertyType != null)
{
var mInfo = typeof(RuntimeInjection).GetMethod("ModifyString");
result = builder.DefineProperty(propertyName,Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
//getIl.Emit(OpCodes.Nop);
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld,fieldBuilder);
if (propertyType.Equals(typeof(string)))
{
getIl.Emit(OpCodes.Call,mInfo);
getIl.Emit(OpCodes.Stloc_0);
getIl.Emit(OpCodes.Br_S);
getIl.Emit(OpCodes.Ldloc_0);
}
getIl.Emit(OpCodes.Ret);
result.SetGetMethod(getPropMthdBldr);
}
if (!isReadOnly)
{
MethodBuilder setPropMthdBldr = builder.DefineMethod("set_" + propertyName,fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
result.SetSetMethod(setPropMthdBldr);
}
}
return result;
}
这是我引用的功能(只是一个虚拟测试对象):
public static class RuntimeInjection
{
public static string ModifyString(string input)
{
return input;
}
}
但是,每次测试时,都会出现错误:“ System.InvalidProgramException:“公共语言运行时检测到无效程序”。 仅当我访问get函数时,该错误才会发生。他能够生成类型,我也可以为属性分配值。
出现错误后,我尝试了多种方法。我写了一个类似的测试属性:
public string Name
{
get
{
return Modify(_name);
}
set
{
_name = value;
}
}
然后我打开IL反汇编程序并签出命令。反汇编程序向我显示了此信息:
我被困在这里,是因为散播者向我展示的内容与我大致相同。 需要一些新鲜的想法,也许您可以提供一些:)。
更新: 我想我发现了可能的问题。 IL_000e:brs。IL_0010
// I think Br_S needs a label to ldloc_0 but i am unsure how to do it. Anyone used Br_S already?
getIl.Emit(OpCodes.Br_S);
getIl.Emit(OpCodes.Ldloc_0);