.NET高级技术_03反射和Attribute

一:反射入门及Type

.Net中的类都被编译成IL,反射就可以在运行时获得类的信息(有哪些方法、字段、构造函数、父类等等信息),还可以动态创建对象、调用成员。

每个类对应一个Type对象,每个方法对应一个MethodInfo对象,每个属性对应一个PropertyInfo……。这些就是类、方法、属性的“元数据”(meta data)。对象和这个类的对象没有直接关系。这些“元数据对象”和成员有关,和对象无关,也就是每个成员对应一个对象。

类元数据Type
获取类信息对象Type

从对象获取:Type type = person.getType();
从类名获取:Type type =typeof(Person);
从全类名(命名空间+类名)获取:Type type = Type.GetType(“com.rupeng.Person”);

这上面三种方法主要根据程序中所要探查的内容不一样,方式也就不一样。如果有一个对象,就用getType()获取;如果没有对象就可以用typeof;如果要运行时通过配置文件等拿到的字符串来获得就要用Type.GetType(“com.rupeng.Person”)。

Activator.CreateInstance(type); //使用无参数构造方法创建此类的对象(如果没有无参构造函数会报异常)。要求类必须有无参构造函数。相当于是new Person();

有同学可能会问可以new为啥还要这样绕一圈?因为在真正的业务中可能我们在写这个代码的时候并不知道我们具体是执行的那个类,所以才会有这样的用法。

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            Person p2 = new Person();
            Person p3 = new Person();

            Type t1 = p1.GetType();
            Type t2 = p2.GetType();
            Type t3 = typeof(Person);
            Type t4 = Type.GetType("NS.Person");
            if (t1 == t2 && t2 == t3 && t3 == t4)
            {
                Console.WriteLine(t1);
            }
            Console.WriteLine(typeof(Program));

            //Activator.CreateInstance(t1)动态创建类,类必须有public且无参的构造函数。
            object obj = Activator.CreateInstance(t1);  //动态创建t1指向的类的对象。new Person();
            Console.WriteLine(obj);

            Console.ReadLine();
        }
    }

    class Person
    {
        public override string ToString()
        {
            return "我是Person";    
        }
    }
}

二:this的本质

this代表“当前对象”,不是“当前类”这个问题在类继承中尤其要注意。在父类中使用this,当创建一个子类对象的时候,去执行有关this的代码就是执行的子类中的实现。

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Parent c1 = new Child1();
            c1.Hello();

            Console.ReadLine();
        }
    }

    class Parent
    {
        public void Hello()
        {
            Type type = this.GetType();  //this不是代表“当前类”,而是代表“当前对象”,this看做当前对象的特殊变量。
            Console.WriteLine(type);
            this.Test();
        }

        public virtual void Test()
        {
            Console.WriteLine("Parent Test");
        }

    }

    class Child1 : Parent
    {
        public override void Test()
        {
            Console.WriteLine("Child1 Test");
        }

    }

    class Child2 : Parent
    {
        public override void Test()
        {
            Console.WriteLine("Child2 Test");
        }
    }
}

三:Type成员

IsInterface、IsArray、IsPrimitive、 IsEnum:是否接口、数组、原始类型、枚举等。

String Name:得到类名(不包含命名空间)
String FullName:得到类名(包含命名空间)
BaseType:得到父类的Type

ConstructorInfo GetConstructor(Type[] types) //获取参数类型匹配的构造函数
ConstructorInfo[] GetConstructors() //获得所有的public构造函数,包括父类的

调用object Invoke(object[] parameters)可以调用构造函数方法

MethodInfo GetMethod(string name, Type[] types)
MethodInfo[] GetMethods() //获得所有的public方法
调用object Invoke(object obj, object[] parameters) //可以调用方法属性

PropertyInfo GetProperty(string name) //获取某个属性
PropertyInfo[] GetProperties() //获取所有属性

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Type t1 = typeof(Person);
            Type t2 = t1.GetType().BaseType.BaseType;
            Console.WriteLine(t2);
            Console.WriteLine(t1.FullName);
            Console.WriteLine(t1.Name);

            Console.WriteLine(t1.IsAbstract);

            Type t3 = typeof(Gender);
            Console.WriteLine(t3.IsEnum);

            int[] nums = { 3, 4, 5, 6 };
            Type t4 = nums.GetType();
            Console.WriteLine(t4.IsArray);

            Console.WriteLine("====================================");

            Type t5 = typeof(Person);
            ConstructorInfo? c1 = t5.GetConstructor(Type.EmptyTypes);
            ConstructorInfo? c2 = t5.GetConstructor(new Type[] { typeof(string) });
            ConstructorInfo? c3 = t5.GetConstructor(new Type[] { typeof(string), typeof(int) });
            ConstructorInfo? c4 = t5.GetConstructor(new Type[] { typeof(string), typeof(string) });
            Console.WriteLine(c1);
            Console.WriteLine(c2);
            Console.WriteLine(c3);
            Console.WriteLine(c4);

            Console.WriteLine("====================================");

            FieldInfo[] fields = t5.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            foreach (var item in fields)
            {
                Console.WriteLine(item);
            }

            Console.WriteLine("====================================");

            MethodInfo[] methods = t5.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            foreach (var item in methods)
            {
                Console.WriteLine(item);
            }

            Console.WriteLine("====================================");

            //MethodInfo? m1 = t5.GetMethod("SayHi");
            MethodInfo? m1 = t5.GetMethod("SayHi", new Type[] { typeof(string)});
            Console.WriteLine(m1);


            Console.WriteLine("====================================");

            PropertyInfo[] properties = t5.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            foreach (var item in properties)
            {
                Console.WriteLine(item);
            }

            Console.WriteLine("====================================");

            PropertyInfo? property = t5.GetProperty("Name");
            Console.WriteLine(property);

            Console.ReadLine();
        }
    }

    enum Gender
    {
        male,
        female,
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name)
        {
            Name = name;
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string? _Name;
        private int _Age;

        public string? Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public int Age
        {
            get { return _Age; }
            set { _Age = value; }
        }

        public void SayHi()
        {
            Console.WriteLine("大家好,我是: " + this.Name + ", 我的年龄:" + this.Age);
        }

        public void SayHi(string s)
        {
            Console.WriteLine("SayHi, " + s);
        }
    }
}

MethodInfo、ConstructorInfo、PropertyInfo父类的主要成员以及各自的主要成员

ConstructorInfo继承自MethodBase,MethodBase继承自MemberInfo。
MethodInfo继承自MethodBase,MethodBase继承自MemberInfo。
PropertyInfo继承自MemberInfo。

MemberInfo主要成员

1、public abstract string Name { get; }
2、public abstract object[] GetCustomAttributes(Type attributeType, bool inherit);

MethodBase主要成员

1、public bool IsAbstract { get; }
2、public bool IsPrivate { get; }
3、public bool IsPublic { get; }
4、public bool IsStatic { get; }
5、public bool IsVirtual { get; }
6、public virtual MethodBody? GetMethodBody(); //反编译方法
7、public object? Invoke(object? obj, object?[]? parameters);

MethodInfo主要成员

1、public virtual Type ReturnType { get; } //返回值的类型

ConstructorInfo主要成员

1、public object Invoke(object?[]? parameters); //调用构造函数

PropertyInfo主要成员

1、public abstract bool CanWrite { get; } //是否可写
2、public abstract bool CanRead { get; } //是否可读
3、public abstract Type PropertyType { get; } //属性值的类型
4、public object? GetValue(object? obj) //获取object对象的属性值
5、public virtual object? GetValue(object? obj, object?[]? index); //给object对象的属性赋值

四:反射演示

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Type t1 = typeof(Person);
            object? obj1 = Activator.CreateInstance(t1);  //new Person();
            object? obj2 = t1.GetConstructor(new Type[0]).Invoke(new object[0]);
            
            PropertyInfo? propertyName = t1.GetProperty("Name");
            propertyName.SetValue(obj2, "lilei");  //obj1.Name = "lilei"
            PropertyInfo? propertyAge = t1.GetProperty("Age");
            propertyAge.SetValue(obj2, 20);

            MethodInfo? methodSayHi1 = t1.GetMethod("SayHi", new Type[0]);
            methodSayHi1.Invoke(obj2, new object[0]);  //在obj2指向的对象上调用SayHi方法,obj2.SayHi

            MethodInfo? methodSayHi2 = t1.GetMethod("SayHi", new Type[] { typeof(string) });
            methodSayHi2.Invoke(obj2, new object[] { "hanmeimei" });

            Console.ReadLine();
        }
    }

    enum Gender
    {
        male,
        female,
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name)
        {
            Name = name;
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string? _Name;
        private int _Age;

        public string? Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public int Age
        {
            get { return _Age; }
            set { _Age = value; }
        }

        public void SayHi()
        {
            Console.WriteLine("大家好,我是 " + this.Name + ", 我的年龄:" + this.Age);
        }

        public void SayHi(string s)
        {
            Console.WriteLine("SayHi, " + s);
        }
    }
}
namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 20;
            ShowObject(p1);
            Console.ReadLine();
        }

        static void ShowObject(object obj)
        {
            Type t = obj.GetType();
            PropertyInfo[] properties = t.GetProperties();
            foreach (var item in properties)
            {
                if (item.CanRead)
                {
                    string propName = item.Name;
                    object? value = item.GetValue(obj, null);
                    Console.WriteLine(propName + " = " + value);
                }
            }
        }
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name)
        {
            Name = name;
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string? _Name;
        private int _Age;

        public string? Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public int Age
        {
            get { return _Age; }
            set { _Age = value; }
        }

        public void SayHi()
        {
            Console.WriteLine("大家好,我是 " + this.Name + ", 我的年龄:" + this.Age);
        }

        public void SayHi(string s)
        {
            Console.WriteLine("SayHi, " + s);
        }
    }
}
namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 20;

            Person? p2 = MyClone(p1) as Person; ;
            p1.Name = "hanmeimei";
            p1.Age = 30;

            p2.SayHi();
            Console.WriteLine(object.ReferenceEquals(p1, p2));

            Console.ReadLine();
        }

        static object MyClone(object obj)
        {
            Type t = obj.GetType();
            object? newobj = Activator.CreateInstance(t);  //创建一个拷贝对象
            foreach (var item in t.GetProperties())  //遍历每个属性
            {
                if (item.CanRead && item.CanWrite)
                {
                    object value = item.GetValue(obj);  //获取obj对象属性的值
                    item.SetValue(newobj, value);  //把值赋值给newobj对应的属性
                }
            }
            return newobj;
        }
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name)
        {
            Name = name;
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string? _Name;
        private int _Age;

        public string? Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public int Age
        {
            get { return _Age; }
            set { _Age = value; }
        }

        public void SayHi()
        {
            Console.WriteLine("大家好,我是 " + this.Name + ", 我的年龄:" + this.Age);
        }
    }
}

五:Attribute简介

标签

常用Attribute
[Obsolete]:表明此成员已过时;
当使用PropertyGrid的时候可以修饰属性;
[ReadOnly(true)]:在编辑器中只读,代码赋值不受影响;
[DisplayName(“姓名”)]:属性的显示名;
[Browsable(false)]:属性是否可见;

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Person p1 = new Person();
            p1.Name = "aoteman";
            p1.Age = 20;
            p1.SayHi();
            propertyGrid1.SelectedObject = p1;
        }
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name)
        {
            Name = name;
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string? _Name;
        private int _Age;

        [ReadOnly(true)]
        [Description("请输入你的名字"), DisplayName("姓名")]
        public string? Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        [Browsable(false)]
        [Description("请输入你的年纪"), DisplayName("年龄")]
        public int Age
        {
            get { return _Age; }
            set { _Age = value; }
        }

        [Obsolete]
        public void SayHi()
        {
            Console.WriteLine("大家好,我是 " + this.Name + ", 我的年龄:" + this.Age);
        }

        public void SayHi(string s)
        {
            Console.WriteLine("SayHi, " + s);
        }
    }
}

六:Attribute语法

Attribute用来在代码中附加一些元信息,这些元信息可被编译器、.net framework、或者我们的程序使用。方法、属性、类等上都可以标注Attribute。

一般起到说明、配置的作用;命名一般以Attribute结尾,如果以Attribute结尾的话使用的时候可以省略Attribute。

注解不会直接影响代码的实际逻辑,仅仅起到辅助性的作用;如果起作用也是编译器、.net framework 、程序去解析的。

在Type、MethodInfo、PropertyInfo等上都可以调用object[] GetCustomAttributes(Type attributeType, bool inherit)获取标注的注解对象,因为同一个Attribute可能标注多次,所以返回值是数组。

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 20;

            Type t1 = typeof(Person);
            //Type t1 = p1.GetType();
            object[] obsoletesAttries = t1.GetCustomAttributes(typeof(ObsoleteAttribute), false);

            if (obsoletesAttries.Length > 0)
            {
                Console.WriteLine("这个类已经过时");
            }
            else 
            {
                Console.WriteLine("这个类没有过时");
            }

            foreach (PropertyInfo prop in t1.GetProperties())
            {
                string name = prop.Name;
                object value = prop.GetValue(p1);
                Console.WriteLine("name:" + name + ", value:" + value);

                string? displayName = null;

                //获取prop上标注的DisplayNameAttribute类型的Attribute的对象
                DisplayNameAttribute? displayNameAttr1 = prop.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute;
                if (displayNameAttr1 == null)  //如果为null就说明没有标注这样一个Attribute
                {
                    displayName = null;
                }
                else
                {
                    displayName = displayNameAttr1.DisplayName;
                }

                PinyinDisplayNameAttribute? pinyinAttr = prop.GetCustomAttribute(typeof(PinyinDisplayNameAttribute)) as PinyinDisplayNameAttribute;
                string? pinyinName = null;
                if (pinyinAttr == null)
                {
                    pinyinName = "没有拼音注释";
                }
                else
                {
                    pinyinName = pinyinAttr.DisplayName;
                }

                Console.WriteLine(name + "(拼音是:" + pinyinName + ") " + "= " + value);

                //object[] displayNameAttr2 = prop.GetCustomAttributes(typeof(DisplayNameAttribute), false);
                //if (displayNameAttr2.Length <= 0)
                //{
                //    displayName = null;
                //}
                //else 
                //{
                //    DisplayNameAttribute? displayAttr = displayNameAttr2[0] as DisplayNameAttribute;
                //    displayName = displayAttr.DisplayName;
                //}

                Console.WriteLine(name + "(" + displayName + ") " + "= " + value);
            }
            Console.ReadLine();
        }
    }

    [Obsolete]
    class Person
    {
        public Person()
        {

        }

        public Person(string name)
        {
            Name = name;
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string? _Name;
        private int _Age;

        [ReadOnly(true)]
        [DisplayName("姓名")]
        [PinyinDisplayName("xingming")]
        public string? Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        [Browsable(false)]
        [DisplayName("年龄")]
        [PinyinDisplayName("nianling")]
        public int Age
        {
            get { return _Age; }
            set { _Age = value; }
        }

        public void SayHi()
        {
            Console.WriteLine("大家好,我是 " + this.Name + ", 我的年龄:" + this.Age);
        }
    }


    class PinyinDisplayNameAttribute : Attribute
    {
        private string? _DisplayName;
        public string? DisplayName
        {
            get { return _DisplayName; }
            set { _DisplayName = value; }
        }

        public PinyinDisplayNameAttribute(string? displayName)
        {
            DisplayName = displayName;
        }
    }
}

MySql查询和写入

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 10;

            Dog d1 = new Dog();
            d1.Name = "wangcai";
            d1.Age = 30;

            SqlForm.Insert(p1);
            SqlForm.Insert(d1);

            Person? p2 = SqlForm.SelectById<Person>(typeof(Person), 1);
            Dog? p3 = SqlForm.SelectById<Dog>(typeof(Dog), 1);
            Console.WriteLine(p2.Name);
            Console.WriteLine(p3.Name);
            Console.ReadLine();
        }
    }

    public class Person
    {
        public UInt64 Id { get; set; }
        public string Name { get; set; }
        public UInt64 Age { get; set; }
    }

    public class Dog
    {
        public UInt64 Id { get; set; }
        public string Name { get; set; }
        public UInt64 Age { get; set; }
    }

    public static class SqlForm
    {
        //约定:
        //1、类名要和表名一致;
        //2、字段名和数据库列名一致;
        //3、主键的名字必须交Id,必须是自动递增,int类型
        public static void Insert(object obj)
        {
            Type type = obj.GetType();  //获取obj对象的类名
            string className = type.Name;  //类名:Person

            //列名的数组
            PropertyInfo[] propertyInfos = type.GetProperties();
            string[] propNames = new string[propertyInfos.Length - 1];
            string[] paramNames = new string[propertyInfos.Length - 1];
            MySqlParameter[] sqlParameters = new MySqlParameter[propertyInfos.Length - 1];

            int count = 0;
            //for (int i = 0; i < propertyInfos.Length; i++)
            //{
            //    string propName = propertyInfos[i].Name;
            //    if (propName != "Id")
            //    {
            //        propNames[count++] = propName;
            //        paramNames[count++] = "@" + propName;
            //    }
            //}

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                string propName = propertyInfo.Name;
                if (propName != "Id")
                {
                    propNames[count] = propName;
                    paramNames[count] = "@" + propName;

                    MySqlParameter sqlParameter = new MySqlParameter();
                    sqlParameter.ParameterName = "@" + propName;
                    sqlParameter.Value = propertyInfo.GetValue(obj, null);
                    sqlParameters[count] = sqlParameter;
                    count++;
                }
            }

            //拼接生成Insert语句
            StringBuilder sbSql = new StringBuilder();
            //Insert into Person(Name,Age) values (@Name,@Age)

            sbSql.Append("Insert into ").Append(className).Append("(");
            sbSql.Append(string.Join(",", propNames)).Append(")").Append(" values(").Append(string.Join(",", paramNames)).Append(")");
            string connStr = "Database=study;Data Source=localhost;User Id=root;Password=zzy;pooling=false;CharSet=utf8;port=4800";
            MySqlHelper.ExecuteNonQuery(connStr, sbSql.ToString(), sqlParameters);
            Console.WriteLine("写入成功!");
        }

        public static T SelectById<T>(Type type, int id) where T : class
        {
            string connStr = "Database=study;Data Source=localhost;User Id=root;Password=zzy;pooling=false;CharSet=utf8;port=4800";
            string className = type.Name;
            string sql = "select * from " + className + " where Id=@Id";
            DataRow dr = MySqlHelper.ExecuteDataRow(connStr, sql, new MySqlParameter("@Id", id));

            T? obj = Activator.CreateInstance(type) as T;

            foreach (var item in type.GetProperties())
            {
                string propName = item.Name;  //属性名就是列名
                object value = dr[propName];  //获取数据库中列的值
                item.SetValue(obj, value);  //给obj对象的item属性赋值为value
            }
            return obj;
        }
    }
}

default (T); //用来获取类型的默认值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值