动态类型阴影基类的属性,并使用Reflection.Emit设置为保护

问题描述 投票:1回答:1

我工作了几天,试图隐藏基类的属性,并使用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的方法返回类型
c# .net cil reflection.emit
1个回答
1
投票

[定义属性时应使用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

© www.soinside.com 2019 - 2024. All rights reserved.