Dynami c вводит свойство базового класса тени и устанавливается в защищенное состояние с помощью Reflection.Emit - PullRequest
1 голос
/ 02 апреля 2020

Я работаю в течение нескольких дней, пытаясь скрыть свойство базового класса и установить свойство производного класса для защищенного с помощью Reflection.Emit. Когда я создаю производный класс и устанавливаю новый для базового свойства, вызываем GetProperties (), он показывает только одно свойство с именем, а свойство производного класса не публикуется c, но вызов типа Dynami c типа GetProperties () показывают появляются два свойства с одинаковыми именами (базовое свойство publi c, а тип dynamici c не publi c). Вот мой код.

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.Publi c, возникает AmbiguousMatchException.

Я искал это Переопределение определений свойств с помощью 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();
        }

показывает одно свойство, но свойство Publi c. Так, как я могу установить свойство для защищенного?

Исправлено
  • Получить метод возврата типа String

1 Ответ

2 голосов
/ 02 апреля 2020

Вы должны использовать CallingConventions.HasThis, когда определяете свою собственность:

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

Вы можете получить больше информации здесь: HasThis & ExplicitThis соглашения о вызовах

По Кстати, это помогает вызвать asmBuilder.Save("xxx.dll") после создания типа. Это позволяет вам получить файл сборки и декомпилировать его с помощью ILSpy. Вам придется использовать AssemblyBuilderAccess.RunAndSave при вызове DefineDynamicAssembly и указать fileName при вызове DefineDynamicModule.

В вашем коде также есть одна ошибка, ваш получатель возвращает Int32, тогда как тип недвижимости String

...