C#之反射与特性

一、反射概念与Type类

1、程序在运行过程中,可以查看其他程序集或本身程序集中的元数据的行为叫做反射。

程序集:项目中所有代码以及嵌入式资源的集合。

元数据:我们编写的程序以及程序内数据。

2、反射的作用:

通过反射可以读取程序集(.dll、.exe)中代码内容

可以根据字符串类名,来动态创建类的对象

可以动态获取对象中的信息(方法、属性、字段)

可以根据字符串方法名称来调用执行

3、反射的常用类

1) Type类:设计用来包含类型的特性,可以获取程序使用的类型的信息。(可以获得一个类包含的成 员与方法。)

扫描二维码关注公众号,回复: 15267888 查看本文章

2)命名空间 using System.Reflection;

//实体人员类
public class Person{
    public string Name;
    public int Age;
    private int _ID;
    
    //属性
    public int ID{
        get{return _ID;}
        set{_ID=value;}
    }
    
    public DisplayID(){
        Console.WriteLine(_ID);
    }
    
    public DisplayName(){
        Console.WriteLine(Name);
    }
    
    public DisplayAge(){
        Console.WriteLine(Age);
    }
}
​

using System.Threading.Tasks; //反射的命名空间
class Demo(){
    public void Test1(){
        Person per =new Person();
        Type tyPersonObj=per.GetType(); //反射定义
        
        //显示类的名称
        Console.WriteLine(tyPersonObj.Name);
        //显示类所属的命名空间
        Console.WriteLine(tyPersonObj.Namespace);
        //显示类所属的程序集
        Console.WriteLine(tyPersonObj.Assembly);
        //获取类是否为公共、密封、私有
        Console.WriteLine(tyPersonObj.IsPublic);//True
        Console.WriteLine(tyPersonObj.IsSealed);//False
        Console.WriteLine(tyPersonObj.IsPrimitive);//False
        //获取字段GetFields()方法
        FieldInfo[] ingoArray=tyPersonObj.GetFields();
        Foreach(FieldInfo item in ingoArray){
            Console.WriteLine(item.Name);
        }
        //获取属性GetProperties()方法
         PropertyInfo[] propArray=tyPersonObj.GetProperties();
        Foreach(PropertyInfo item in propArray){
            Console.WriteLine(item.Name);
        }
        //获取方法GetMethods()方法
         MethodInfo[] metgodArray=tyPersonObj.GetMethods();
        Foreach(MethodInfo item in metgodArray){
            Console.WriteLine(item.Name);
        }
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test1();
    }
}

二、程序集Assembly与动态调用

1) Assembly类:得到一个程序集中的反射信息

2)使用反射技术,来动态调用

缺点:运行速度慢

优点:可以使得类对象之间的调用关系在“运行期”进行低耦合调用,可以随着配置文件的改变进行改变。

3)程序集中的两种存在方式

*.dll形式存在的程序集(不能直接运行,是“类库”)

*.exe的程序集,可以点击直接运行

如何加载程序集:

Assembly.Load();//不推荐使用

Assembly.LoadFrom(“程序集的完整路径名称”);

//学习Assembly程序集
using System.Reflection;
class Demo{
    public void Test1(){
        //通过路径直接得到程序集的对象
        Assembly assObj=Assembly.LoadFrom(@"E:\System.dll");
        //通过程序及,得到程序集中所有的类
        Type[] typArray=assObj.GetTypes();
        foreach(Type item in typArray){
            Console.WriteLine(item.Name);
        }
        //根据类名与方法名(字符串),动态调用
        Type type=assObj.GetType("类名字符串");//包含命名空间的类名
        //根据type创建对象
        Object obj=Activator.CreateInstance(type);//动态调用类的无参构造方法
        //获得方法信息
        //Type[] typeArrayWuthPara={type(int)};//重载有参数确定方法重载中有参数
        MethodInfo method=type.GetMethod("方法名称字符串");//如果需要重载,则需要在后面添加一个新                                                        //的参数new Type[0],表示重载无参,重                                                       //载有参则调用新定义的Type数组名                                                             //typeArrayWuthPara
        //调用有参时添加的语句
        //object[] objArray=new object[1];
        //object[0]=参数;
        //调用方法
        method.Invoke(obj,null);//null表示没有参数,如果调用有参方法,null需要换成object数组名
    }
    static void Main(string[] args){
        Demo obj=new Dmeo();
        Obj.Test1();
    }
}

反射调用私有方法与属性

class Person{
    private int _ID;
    //属性
    public int ID{
        get{return _ID;}
        set{_ID=value;}
    }
    public void DisplayPrivate(){
        Console.WriteLine("person类,私有方法,一般情况不可能调用");
    }
}
​
using System.Reflection;
class Demo{
    //调用私有方法
    public void Test1(){
        string strClassName="Person";
        string strMethodName="DisplayPrivate";
        Assembly assObj=Assembly.LoadFrom(strClassName);
        //根据类名与方法名(字符串),动态调用
        Type type=assObj.GetType("类名字符串");//包含命名空间的类名
        //根据type创建对象
        Object obj=Activator.CreateInstance(type);//动态调用类的无参构造方法
        MethodInfo method=
            type.GetMethod("strMethodName",BindingFlags.NonPublic|BindingFlags.Instance);
        method.Invoke(obj,null);
    }
    //调用属性
    public void Test2(){
        string strClassName="Person";//类的名称
        string strPropertydName="ID";//属性的名称
        Assembly assObj=Assembly.LoadFrom(strClassName);
        //根据类名与方法名(字符串),动态调用
        Type type=assObj.GetType("类名字符串");//包含命名空间的类名
        //根据type创建对象
        Object obj=Activator.CreateInstance(type);//动态调用类的无参构造方法
        //获得属性
        PropertyInfo prop=type.Getproperty(strPropertydName);
        //设置属性
        prop.SetValue(obj,100);
        //得到属性值
        string result=prop.GetValue(obj,null).ToString();
        Console.WriteLine(result);
    }
    static void Main(string[] args){
        Demo obj=new Dmeo();
        Obj.Test1();
        Obj.Test2();
    }
}

三、Type深入方法

bool IsAssignableFrom(Type c) //用来判断一个类或接口是否另一个类的父类或接口

bool IsInstanceOfType(object o)//判读对象o 是否是当前类(或者子类)的实例,或者实现本接口

bool IsSubclassOf(Type c)//判断当前类是否为类c (参数)的子类

//父类
public class Men{}
//子类
public class ZhangSan:Men,ICanSpeak{}
//普通类 无继承
public class Dog{}
//接口
interface ICanSpeak{}
//学习Type更多的方法
//1.判断一个类是否为(参数)类的父类或者接口
//
//
//
using System.Reflection;
class Demo{
    //bool IsAssignableFrom(Type c) //用来判断一个类或接口是否另一个类的父类或接口
    public void Test1(){
        Type typeMen=typeof(Men);
        Type typeZhangSan=typeof(ZhangSan);
        Type typeDog=typeof(Dog);
        Type typeICanSpeak==typeof(ICanSpeak);
        //判断Men是ZhangSan的父类吗
        Console.WriteLine(typeMen.IsAssignableFrom(typeZhangSan));//true
        //判断Men是Dog的父类吗
        Console.WriteLine(typeMen.IsAssignableFrom(typeDog));//False
        //判断ICanSpeak是否为ZhangSan的接口
        Console.WriteLine(typeICanSpeak.IsAssignableFrom(typeZhangSan));//true
        //判断ICanSpeak是否为Dog的接口
        Console.WriteLine(typeICanSpeak.IsAssignableFrom(Dog));//false
    }
    //bool IsInstanceOfType(object o)//判读对象o 是否是当前类(或者子类)的实例,或者实现本接口
    public void Test2(){
        Type typeMen=typeof(Men);
        Type typeICanSpeak==typeof(ICanSpeak);
        Men MenObj=new Men();
        ZhangSan zhangsanObj=new ZhangSan();
        Dog dogObj=new Dog();
        //typeMen是MenObj的实例吗?
        Console.WriteLine(typeMen.IsInstanceOfType(MenObj));//T
        Console.WriteLine(typeMen.IsInstanceOfType(zhangsanObj));//T
        Console.WriteLine(typeMen.IsInstanceOfType(dogObj));//F
        Console.WriteLine(typeICanSpeak.IsInstanceOfType(zhangsanObj));//T
        Console.WriteLine(typeICanSpeak.IsInstanceOfType(MenObj));//F
    }
    //bool IsSubclassOf(Type c)//判断当前类是否为类c (参数)的子类 
    public void Test3(){
        Type typeMen=typeof(Men);
        Type typeZhangSan=typeof(ZhangSan);
        Type typeDog=typeof(Dog);
        Console.WriteLine(typeZhangSan.IsSubclassOf(typeMen));  //T
        Console.WriteLine(typeDog.IsSubclassOf(typeMen));//F
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test1();
        obj.Test2();
        obj.Test3();
    }
}

四、预定义特性Attribute

1.特性(Attribute)是一种允许我们向程序集增加元数据的语言结构,提供了一种将声明性信息与代码关联起来的途径。

2.Obsolete特性将过时的方法与类标注为“过时”(过期)的,且在编译时,显示警告信息。

3.Conditional特性一般用于程序开发过程中的“测试方法”的编写。测试阶段定义“测试的宏”,发布商业版本,则取消宏即可。

/*
    学习特性
    一:系统特性
        1:Obsolete特性(即:过时特性)
        2:Conditional特性 
        3:Serializable 声明结构可以被序列化
        4:NonSerialized 声明结构不可以被序列化
        5:DLLImport 声明是非托管代码实现的
    二、自定义特性
    三、条件编译
        1.特性Conditional 适用条件:针对方法
        2.使用"预编译”指令 #if debug  
                            表达式
                        #else
                            表达式
                        #endif
*/
#define OnlyTest //定义一个宏,表示允许Conditional特性标识的测试方法允许
#define debug //定义一个宏,表示调试阶段debug允许运行,但else不允许允许
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Therading.Tasks;
using System.Reflection;//反射的命名空间
using System.Diagnostics;//Conditional特性的命名空间,Obsolete不受影响
namespace 学习特性{
    class Demo1{
        
         //学习Obsolete如果加参数True,旧方法不可用,会引发错误,不加则默认false仅提醒自定义的字符串
        [Obsolete("该方法已过时,请用对应的NewMethod进行替换",true)]
        public void OldMethod(){
            Console.WriteLine("这是旧的方法");
        }
        public void NewMethod(){
             Console.WriteLine("这是新的方法");
        }
        public void Test1(){
            //OldMethod();
            NewMethod();
        }
         
        //学习Conditional ,条件执行,默认不执行
        [Conditional("OnlyTest")]
        public void TestMethod(){
            Console.WriteLine("这是测试方法");
        }
        public void Method1(){
            Console.WriteLine("这是方法1");
        }
        public void Method2(){
            Console.WriteLine("这是方法2");
        }
        //条件编译
        public void Test3(){
            Console.WriteLine("这是条件编译");
            Console.WriteLine("aaa");
#if debug
            Console.WriteLine("bbb");
#else
            Console.WriteLine("ccc");
#endif
            Console.WriteLine("ddd");
        }
        public void Test2(){
            TestMethod();
            Method2;
            TestMethod();
            Method1;
            TestMethod();
            Method1;
            Method2;
            Method1;
        }
        static void Main(string[] args){
            Demo1 obj=new Demo1();
            obj.Test1();
            obj.Test2();
            obj.Test3();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_49251429/article/details/123170551