动态类型 shadow base class 的 属性 并使用 Reflection.Emit 设置为受保护

Dynamic type shadow base class's property and set to protected using Reflection.Emit

我工作了几天,尝试隐藏基础 class 的 属性 并将派生的 class 属性 设置为使用 Reflection.Emit 保护。当我创建派生 class 并将新设置为基础 属性 时,调用 GetProperties() 它只显示一个 属性 名称和派生 class 属性 不是 public,但是动态类型调用 GetProperties() 显示出现了两个同名的属性(基础 属性 是 public 而动态类型不是 public)。这是我的代码。

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。那么如何将 属性 设置为受保护?

固定的

定义 属性 时应使用 CallingConventions.HasThis :

tbuilder.DefineProperty("Name", 
                        PropertyAttributes.HasDefault, 
                        CallingConventions.HasThis,
                        typeof(System.String), 
                        null);

您可以在此处获得更多信息:

顺便说一句,创建类型后调用 asmBuilder.Save("xxx.dll") 会有所帮助。它允许您获取程序集文件并使用 ILSpy 对其进行反编译。您必须在调用 DefineDynamicAssembly 时使用 AssemblyBuilderAccess.RunAndSave 并在调用 DefineDynamicModule.

时指定 fileName

您的代码中还有一个错误,您的 getter return 和 Int32 而 属性 的类型是 String