C#反射(通过反射的方法,获取成员,并调用成员)(通过反射更新功能)

1.通过反射的方法,获取成员,并调用成员

1.把想要反射调用的内容存放到object中,如:

class Student
    {
        public int Id { get; set; }
        public int Age;
        public void Show()
        {
            Console.WriteLine("this is show");
        }
        public string Show2(string name)
        {
            return $"{name}";
        }
    }
static void Main(string[] args)
 {
//把Student类放到 object中 用反射调用的内容
            object obj = new Student();

    }

2.重点:使用object类中的Type类|;返回当前实例的准确运行类型,而不是对象

 Type type = obj.GetType();

3.Type类常用属性

//Type常用属性 FullName完全限定名
 Console.WriteLine(type.Namespace);//获取命名空间
 Console.WriteLine(type.FullName);//获取该类型的完全限定名称--命名空间+类名
 Console.WriteLine(type.Name);//获取当前成员的名称--类名

4.Type常用API:

获取引用类的字段:type.GetFields();type.GetField()

获取引用类的属性:type.GetProperties();type.GetPropertie()

获取引用类的方法:type.GetMethod().Invoke();type.GetMethods().Invoke()

注意:只能获取公共字段;还有获取接口,获取所有方法,就不在细说了,有兴趣的可以自己了解;

4.1获取引用类的字段:获取所有公共字段type.GetFields();获取特定字段:type.GetField()

注意:当字段属性不一致时,不能使用foreach循环赋值;

//----------------------------循环获取所有公共字段 : type.GetFields()
            foreach (var s in type.GetFields())
            {
                //循环找到,再了解信息
                //即获取字段的名字
                if (s.Name == "Age")
                {
                    Console.WriteLine(s.Name);
                    Console.WriteLine(s.FieldType.FullName);
                    s.SetValue(obj, 12);
                    Console.WriteLine(s.GetValue(obj));
//在获取值或取值时,就用到上面说的type是一个,而s只知道是学生类型的字段,并不知道是哪个对象的字段,因此需要加上对象

//简单的说就是获取特定字段用   type.GetField().*** type还是一个,用的时候不知道对象是谁,因此需要传对象。这样在去理解循环遍历就好理解了:s可与理解问type.GetField
                }
            }
//-----------------------------获取特定字段 直接给 GetFiled()赋值字段名-------------
            type.GetField("Age").SetValue(obj, 30);//取出并赋值
            Console.WriteLine(type.GetField("Age").GetValue(obj));

4.2获取属性type.GetProperties()和获取字段一样

4.3  详细内容看标题2

获取引用类的方法有点特别type.GetMethod()需要用到 Invoke(object,object[]参数列表)使用指定参数调用由当前实例表示的方法或实例,看代码

 type.GetMethod("Show").Invoke(obj,new object[0]);
  object str= type.GetMethod("Show2").Invoke(obj, new object[] { "王五"});
  Console.WriteLine(str);

完整代码:

       static void Main(string[] args)
        {

            //反射:
            // 1.通过反射的方法,可以遍历成员,并调用成员
            //把Student类放到 object中 用反射调用的内容
            object obj = new Student();
            //Type是个类
            Type type = obj.GetType();//返回当前实例的准确运行类型 注意是类型,不是对象,后面用
            //Type常用属性 FullName完全限定名
            Console.WriteLine(type.Namespace);
            Console.WriteLine(type.FullName);//获取该类型的完全限定名称--命名空间+类名
            Console.WriteLine(type.Name);//获取当前成员的名称--类名
            #region 字段获取 GetFields(),GetField()

            //----------------------------循环获取所有公共字段 : type.GetFields()
            foreach (var s in type.GetFields())
            {
                //循环找到,再了解信息
                //即获取字段的名字
                if (s.Name == "Age")
                {
                    Console.WriteLine(s.Name);
                    Console.WriteLine(s.FieldType.FullName);
                    s.SetValue(obj, 12);
                    Console.WriteLine(s.GetValue(obj));//在获取值或取值时,就用到上面说的s只知道是学生类型的字段,并不知道是哪个对象的字段,因此需要加上对象
                }
            }
            //-----------------------------获取特定字段 直接给 GetFiled()赋值字段名
            type.GetField("Age").SetValue(obj, 30);//取出并赋值
            Console.WriteLine(type.GetField("Age").GetValue(obj));
            #endregion

            //获取属性  
            Console.WriteLine("--------------------------属性-------------------");
            foreach (var s in type.GetProperties())
            {
                s.SetValue(obj, 1);
                Console.WriteLine(s.GetValue(obj));
            }
            type.GetProperty("Id").SetValue(obj, 2);
            Console.WriteLine(type.GetProperty("Id").GetValue(obj));


            type.GetMethods();//获取所有公共方法
            //Invoke(object,object[]参数列表)使用指定参数调用由当前实例表示的方法或实例
            type.GetMethod("Show").Invoke(obj, new object[0]);
            object str = type.GetMethod("Show2").Invoke(obj, new object[] { "王五" });
            Console.WriteLine(str);
            type.GetMembers();
            Console.ReadKey();
        }

    }
    class Student
    {
        public int Id { get; set; }
        public int Age;
        public void Show()
        {
            Console.WriteLine("this is show");
        }
        public string Show2(string name)
        {
            return $"{name}";
        }
    }

2.反射调用不同参数的方法,返回结果有何不同

在后面的学习中发现了一个有趣的地方,当方法的参数不同时,返回的结果有不同,对此我做了总结,可以分为以下几种:

1.方法没有参数,且输出语句没有用到类中字段或属性;

答:正常输

2.方法没有传参,且输出语句用到类中字段或属性,且字段和属性没有赋值;已经赋值;

答:使用没有赋值,就默认初始值;使用赋值就是输出此值

3.方法传参数,但是此参数不属于字段或属性;

答:不影响,输出所传内容;

4.方法传参数,此参数属于类中字段或属性,已经赋值,没有赋值;

答:一切按照所传参数进行输出

class Student
    {
        public int Id { get; set; }
        public int Age;
        public string Name { get; set; }
        //1.方法没有参数,且输出语句没有用到类中字段或属性;
        public void Show()
        {
            Console.WriteLine("this is show");
        }
        //2.不传参数,直接使用属性或字段
        public void Show2()
        {
            Console.WriteLine("我是:" + Id);
        }
        //3.传一个就不是字段又不是属性的参数
        public void Show3(string fullname)
        {
            Console.WriteLine("我是:" + fullname);
        }
        //4.传一个属于字段或属性的字段
        public void Show5(int Age)
        {
            Console.WriteLine("我是:" + Age);
        }
        //在name属性复赋值前后,都调用
        public void Show6(string name)
        {
            Console.WriteLine("我是:" + name);
        }
/--------------------输出-----------------
 type.GetMethod("Show").Invoke(obj, new object[0]);//this is show
            type.GetMethod("Show2").Invoke(obj, new object[0]);//我是:0
            type.GetProperty("Id").SetValue(obj, 2);
            type.GetMethod("Show2").Invoke(obj, new object[0]);//我是:2
            type.GetMethod("Show3").Invoke(obj, new object[] { "fullname" }); //我是:fullname
            type.GetMethod("Show5").Invoke(obj, new object[] { 18 });//我是:18
            type.GetField("Age").SetValue(obj, 12);
            type.GetMethod("Show5").Invoke(obj, new object[] { 18 });//我是:18
            type.GetMethod("Show6").Invoke(obj, new object[] { "张三" }); //我是:张三
            type.GetProperty("Name").SetValue(obj, "李四");
            type.GetMethod("Show6").Invoke(obj, new object[] { "王五" }); //我是:王五

3.通过反射更新功能

动态引用一个dell 文件类库(普通dell文件,不是专门封装成方法的dell文件:比如放一个类在里面)

public class Class1
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public void Test()
        {
            Console.WriteLine($"你好我是{Name},今年{Age}岁了");
        }

前提操作:

1.生成类库;2.打开类库所在文件夹,找到dell文件;3.复制到目标项目中4.点击复制到目标项目中的dell文件,属性,复制到输出目录改如果较新则更新;5.记得打开显示全部文件;6.刷新;

2.通过代码程序集Assembly 引用一下dell文件

//引用一个dell问价 类库
            //一个程序集           加载指定路径上的程序集文件的内容
            Assembly ass = Assembly.LoadFile(Environment.CurrentDirectory + @"\libs\ClassLibrary1.dll");

3.此时就可以对引入的dell文件判断操作了

 foreach (var type in ass.GetTypes())
            {
                Console.WriteLine(type.Name);
                Console.WriteLine(type.FullName);
                //判断是否含有***,不存在返回flase;通过一系列的is属性进行过滤
                Console.WriteLine(type.IsClass);
                Console.WriteLine(type.IsEnum);
            }
            //.First返回序列表的第一个元素
            var classs = ass.GetTypes().First(x => !x.IsEnum && x.IsClass);
            Console.WriteLine(classs.FullName);
            //注意:这里的user没有对象,但能不能生成一个呢
            //如何创建
            // CreateInstance  从程序集中查找指定的类型,然后使用系统激活器创建它的实例
            object obj= ass.CreateInstance(classs.FullName);//相当于把类又放到了object中
            //下面的就和之前的一样了
            classs.GetProperty("Age").SetValue(obj,12);
            classs.GetProperty("Name").SetValue(obj,"李四");
            classs.GetMethod("Test").Invoke(obj, null);//注意
            Console.WriteLine(classs.GetProperty("Name").GetValue(obj));
            Console.WriteLine(classs.GetProperty("Age").GetValue(obj));
            Console.WriteLine(classs.GetMethod("Test").Invoke(obj, null));

4.更新类库

 public class Class1
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public void Test2()
        {
            Console.WriteLine("我是更新类库");
        }
        public void Test()
        {
            Console.WriteLine($"你好我是{Name},今年{Age}岁了");
            Test2();
        }
    }

,4.1将更改的类库重新生成,并替换掉目项目原来的dell,此时代码不动,结果如下

 可以理解为 Test是一个按钮,Test2是增加了一个功能;

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薄荷撞~可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值