我工作了几天,试图隐藏基类的属性,并使用Reflection.Emit将派生类的属性设置为protected。当我创建派生类并将new设置为基本属性时,调用GetProperties()只会显示一个具有名称的属性,而派生类的属性不是公共的,但是动态类型调用GetProperties()显示两个具有相同名称的属性出现(基本属性是公共属性,动态类型不是公共属性)。这是我的代码。
namespace ILHiddenProperty
{
interface IILName
{
string Name { get; set; }
}
public class ClassName : IILName
{
public string Name { get; set; } = "ClassName";
}
public class ChildName : ClassName
{
protected new string Name { get; set; } = "ChildName";
}
public class NameILGenerator
{
public static Type ILType()
{
AssemblyName aname = new AssemblyName("MyAssembly");
AppDomain currentDomain = AppDomain.CurrentDomain; // Thread.GetDomain();
AssemblyBuilder asmbuilder = currentDomain.DefineDynamicAssembly(aname,
AssemblyBuilderAccess.Run);
ModuleBuilder mbuilder = asmbuilder.DefineDynamicModule("EmitMethods");
TypeBuilder tbuilder = mbuilder.DefineType("ILName", TypeAttributes.Public,typeof(ClassName));
FieldBuilder fName = tbuilder.DefineField("_name", typeof(System.String), FieldAttributes.Private);
PropertyBuilder pName = tbuilder.DefineProperty("Name", PropertyAttributes.HasDefault, typeof(System.String), null);
//Getter
MethodBuilder mNameGet = tbuilder.DefineMethod("get_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
typeof(System.String),
Type.EmptyTypes);
ILGenerator nameGetIL = mNameGet.GetILGenerator();
nameGetIL.Emit(OpCodes.Ldarg_0);
nameGetIL.Emit(OpCodes.Ldfld, fName);
nameGetIL.Emit(OpCodes.Ret);
//Setter
MethodBuilder mNameSet = tbuilder.DefineMethod("set_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null,
new Type[] { typeof(System.String) });
ILGenerator nameSetIL = mNameSet.GetILGenerator();
nameSetIL.Emit(OpCodes.Ldarg_0);
nameSetIL.Emit(OpCodes.Ldarg_1);
nameSetIL.Emit(OpCodes.Stfld, fName);
nameSetIL.Emit(OpCodes.Ret);
pName.SetGetMethod(mNameGet);
pName.SetSetMethod(mNameSet);
return tbuilder.CreateType();
}
}
}
namespace ILHiddenProperty
{
class Program
{
static void Main(string[] args)
{
PrintNameProperty(typeof(ClassName));
PrintNameProperty(typeof(ChildName));
PrintNameProperty(NameILGenerator.ILType());
Console.Read();
}
public static void PrintNameProperty(Type nameType)
{
var props = nameType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach(var prop in props)
{
Console.WriteLine("{0}.{1} IsPublic:{2}",nameType.Name, prop.Name, prop.GetMethod.IsPublic);
}
}
}
}
我尝试添加MethodAttributes.NewSlot,但没有成功。当我将MethodAttributes.Family更改为MethodAttributes.Public时,出现了AmbiguousMatchException。
我搜索了此Overriding property definitions with Reflection.Emit,并更改了ILType以不定义属性,而仅定义get和set函数
public static Type ILType()
{
AssemblyName aname = new AssemblyName("MyAssembly");
AppDomain currentDomain = AppDomain.CurrentDomain; // Thread.GetDomain();
AssemblyBuilder asmbuilder = currentDomain.DefineDynamicAssembly(aname,
AssemblyBuilderAccess.Run);
ModuleBuilder mbuilder = asmbuilder.DefineDynamicModule("EmitMethods");
TypeBuilder tbuilder = mbuilder.DefineType("ILName", TypeAttributes.Public,typeof(ClassName));
FieldBuilder fName = tbuilder.DefineField("_name", typeof(System.String), FieldAttributes.Private);
//PropertyBuilder pName = tbuilder.DefineProperty("Name", PropertyAttributes.HasDefault, typeof(System.String), null);
//Getter
MethodBuilder mNameGet = tbuilder.DefineMethod("get_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
typeof(System.String),
Type.EmptyTypes);
ILGenerator nameGetIL = mNameGet.GetILGenerator();
nameGetIL.Emit(OpCodes.Ldarg_0);
nameGetIL.Emit(OpCodes.Ldfld, fName);
nameGetIL.Emit(OpCodes.Ret);
//Setter
MethodBuilder mNameSet = tbuilder.DefineMethod("set_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null,
new Type[] { typeof(System.String) });
ILGenerator nameSetIL = mNameSet.GetILGenerator();
nameSetIL.Emit(OpCodes.Ldarg_0);
nameSetIL.Emit(OpCodes.Ldarg_1);
nameSetIL.Emit(OpCodes.Stfld, fName);
nameSetIL.Emit(OpCodes.Ret);
//pName.SetGetMethod(mNameGet);
//pName.SetSetMethod(mNameSet);
return tbuilder.CreateType();
}
它显示一个属性,但该属性是Public。那么如何将属性设置为保护?
固定String
的方法返回类型[定义属性时应使用CallingConventions.HasThis
:
tbuilder.DefineProperty("Name",
PropertyAttributes.HasDefault,
CallingConventions.HasThis,
typeof(System.String),
null);
您可以在此处获得更多信息:HasThis & ExplicitThis calling conventions
顺便说一句,创建类型后调用asmBuilder.Save("xxx.dll")
很有帮助。它允许您获取程序集文件并使用ILSpy对其进行反编译。调用AssemblyBuilderAccess.RunAndSave
时必须使用DefineDynamicAssembly
,并在调用fileName
时指定DefineDynamicModule
。
您的代码中还有一个错误,您的getter返回一个Int32
,而该属性的类型为String