IL接口和类的属性

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IL接口和类的属性相关的知识,希望对你有一定的参考价值。

   上一篇文章学习了IL的入门,接下来我们再通过两个例子来了解下类的属性、构造函数以及接口的使用

一、类的属性、构造函数

1、先看下我们要构建的类的C#代码,然后再进行IL的实现,示例代码如下:

技术分享
    [Serializable]
    public class Dynamic
    {
        public int _a = 0;
        public const string ConstField = "const";

        /// <summary>
        /// 定义属性
        /// </summary>
        public int A { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="num"></param>
        public Dynamic(int num)
        {
            this.A = num;
        }

        public int Add(int num)
        {
            return this.A + num;
        }
    }
View Code

2、通过以上代码我们可以根据要求先定义字段_a、常量ConstField(在构造函数过程中未使用到,帮组了解类属性的创建)以及给类加上序列化标签,属性可以通过TypeBuilder的DefineField创建,而序列化标签需要通过TypeBuilder的CustomAttributeBuilder去创建,示例代码如下:

技术分享
            //定义类可序列化
            CustomAttributeBuilder serializable = new CustomAttributeBuilder(typeof(SerializableAttribute).GetConstructor(Type.EmptyTypes), new Type[] { });
            typeBuilder.SetCustomAttribute(serializable);

            //定义常量
            FieldBuilder fieldConst = typeBuilder.DefineField("ConstField", typeof(string), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.Literal);
            fieldConst.SetConstant("const");

            //定义字段_a
            FieldBuilder aField = typeBuilder.DefineField("_a", typeof(int), FieldAttributes.Private);
            aField.SetConstant(0);
View Code

3、通过TypeBuilder的DefineProperty定义属性A,通过CustomAttributeBuilder给属性添加对应的标签,示例代码如下:

技术分享
            //定义属性A
            PropertyBuilder propertyABuilder = typeBuilder.DefineProperty("A", PropertyAttributes.None, typeof(int), null);
            CustomAttributeBuilder desAttributeBuilder = new CustomAttributeBuilder(typeof(DescriptionAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { "属性A" });
            propertyABuilder.SetCustomAttribute(desAttributeBuilder);//字段描述
View Code

4、定义A属性的get方法和set方法,get和set方法和普通的方法创建相同,用TypeBuilder的DefineMethod创建。示例代码如下:

技术分享
            //定义属性get方法
            MethodBuilder methodABuilder = typeBuilder.DefineMethod("get", MethodAttributes.Public, typeof(Int32), Type.EmptyTypes);
            ILGenerator GetIL = methodABuilder.GetILGenerator();
            GetIL.Emit(OpCodes.Ldarg_0);
            GetIL.Emit(OpCodes.Ldfld, aField);
            GetIL.Emit(OpCodes.Ret);
            propertyABuilder.SetGetMethod(methodABuilder);

            //定义属性set方法
            MethodBuilder methodBBuilder = typeBuilder.DefineMethod("set", MethodAttributes.Public, typeof(Int32), new Type[] { typeof(Int32) });
            ILGenerator SetIL = methodBBuilder.GetILGenerator();
            SetIL.Emit(OpCodes.Ldarg_0);
            SetIL.Emit(OpCodes.Ldarg_1);
            SetIL.Emit(OpCodes.Stfld, aField);
            SetIL.Emit(OpCodes.Ret);
            propertyABuilder.SetSetMethod(methodBBuilder);
View Code

5、构造函数的创建,构造函数是通过TypeBuilder的DefineConstructor去获取,构造函数包含一个参数并赋值给_a,示例代码如下:

技术分享
            //定义构造函数
            ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeof(Int32) });

            ILGenerator constructorIL = constructorBuilder.GetILGenerator();
            constructorIL.Emit(OpCodes.Ldarg_0);
            constructorIL.Emit(OpCodes.Ldarg_1);
            constructorIL.Emit(OpCodes.Stfld, aField);
            constructorIL.Emit(OpCodes.Ret);
View Code

6、最后是定义方法。

技术分享
            //定义方法
            MethodBuilder methodAddBuild = typeBuilder.DefineMethod("Add", MethodAttributes.Public, typeof(Int32), new Type[] { typeof(int) });
            ILGenerator addIL = methodAddBuild.GetILGenerator();
            addIL.Emit(OpCodes.Ldarg_0);
            addIL.Emit(OpCodes.Ldfld, aField);
            addIL.Emit(OpCodes.Ldarg_1);
            addIL.Emit(OpCodes.Add);
            addIL.Emit(OpCodes.Ret);
View Code

到这一步一个动态类包含的属性、构造函数以及方法就创建完成。可以借助reflector看下生成的结果。如下:

技术分享

public int A { get; set; }
换成
public int A5
{
get { return _a; }
set { _a = value; }
}
比较容易理解_a的存在

 二、接口的实现

1、首先我们看下我们要实现一个什么样的接口,先看下构建类的C#代码,示例代码如下:

技术分享
    public class Mail : IMail
    {

        public string SendMail()
        {
            return "Send Success";
        }
    }

    public interface IMail
    {
        string SendMail();
    }
View Code

2、实现接口,接口我们直接用IMail这个。就不用IL去创建了,首先我们创建一个typeBuilder,指定继承接口IMail,可以用AddInterfaceImplementation来进行操作。示例代码如下:

技术分享
            //定义类型
            TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public);
            typeBuilder.AddInterfaceImplementation(typeof(IMail));
View Code

3、实现接口。接口实现方法要怎么定义在不清楚的情况下可以用reflector反编译一个实现接口的方法来查看一下,观察一下方法需要哪些MethodAttributes属性。

技术分享

通过以上信息可以定义接口实现的方法,接口实现就和之前例子定义的方法实现一样。示例代码如下:

技术分享
            MethodBuilder sendMailBuilder = typeBuilder.DefineMethod("SendMail", MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(string), null);
            //定义接口
            ILGenerator mailIL = sendMailBuilder.GetILGenerator();
            LocalBuilder resultStr = mailIL.DeclareLocal(typeof(String));
            mailIL.Emit(OpCodes.Nop);
            mailIL.Emit(OpCodes.Ldstr, "Send Success1");
            mailIL.Emit(OpCodes.Stloc_0);
            mailIL.Emit(OpCodes.Ldloc_0);
            mailIL.Emit(OpCodes.Ret);
View Code

实现后通过IL查看的代码如下:

技术分享

  通过反编译发现,接口实现是带有override关键字的。而在定义实现方法时候如果不带上virtual属性又会提示接口未实现。也请知道的朋友解决下我的疑惑。

  通过这篇文章我们了解到了动态类的创建,也了解到了接口的使用。从这两个示例其实可以拓展出很多的东西比如继承、属性绑定自定义标签、虚方法的重写......这些东西也是需要不断学习才能了解。在IL这块的学习还有比较多的不懂在之后的学习再分享。
示例代码下载:IL-3



以上是关于IL接口和类的属性的主要内容,如果未能解决你的问题,请参考以下文章

java接口和类的区别在那里.

类的继承和类继承运用

java中接口和类有啥区别java中接口和类有啥区别

小峰视频十四:面向对象和类的概念

java接口和类有啥区别?

类的关系