美文网首页
C# 反射 typeof GetType

C# 反射 typeof GetType

作者: 合肥黑 | 来源:发表于2022-01-28 09:59 被阅读0次
    一、typeof GetType

    参考
    Unity C# 游戏开发 反射 Reflection 案例讲解(图文详细,带源码)
    C# typeof() 和 GetType()区别

    using System;
    using System.Reflection;
    using UnityEngine;
    
    public class FindOfReflection : MonoBehaviour
    {
        private ReflectionTest reflectionTest;
    
    
        private void Awake()
        {
            reflectionTest = new ReflectionTest();
        }
        void Start()
        {
            SeeConstructor();
            SeeProperty();
            SeePublicMethod();
            SeePublicField();
    
            CreatObjectByConstruct();
            CreatObjByActivator();
    
            CreatAndSet();
        }
    
        private void SeeConstructor()
        {
            //获取reflectionTest的Type
            Type type = reflectionTest.GetType();
            //通过Type获取这个类的所有构造函数信息
            ConstructorInfo[] constructorArray = type.GetConstructors();
            foreach (ConstructorInfo constructorInfo in constructorArray)
            {
                Debug.Log("=====================" + constructorInfo.ToString());
                //获取每个构造函数的所有参数
                ParameterInfo[] parameterArray = constructorInfo.GetParameters();
                foreach (ParameterInfo parameterInfo in parameterArray)
                {
                    Debug.Log("数据类型:" + parameterInfo.ParameterType.ToString() + "\n" + "参数名字:" + parameterInfo.Name);
                }
            }
        }
    
        private void SeeProperty()
        {
            //获取reflectionTest的Type
            Type type = reflectionTest.GetType();
            //获取所有属性信息
            PropertyInfo[] propertyInfos = type.GetProperties();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                //打印出来属性的名字
                Debug.Log("属性:" + propertyInfo.Name);
            }
        }
    
        private void SeePublicMethod()
        {
            Type type = reflectionTest.GetType();
            //通过type获取所有公开方法的信息
            MethodInfo[] methodInfos = type.GetMethods();
            foreach (MethodInfo methodInfo in methodInfos)
            {
                Debug.Log("公开方法的返回类型:" + methodInfo.ReturnType + "---" + "方法的名字:" + methodInfo.Name);
            }
        }
    
        private void SeePublicField()
        {
            Type type = reflectionTest.GetType();
            //通过type获取所有公开的字段的信息
            FieldInfo[] fieldInfos = type.GetFields();
            foreach (FieldInfo fieldInfo in fieldInfos)
            {
                Debug.Log("公开的字段的名字:" + fieldInfo.Name);
            }
        }
    
        /// <summary>
        /// 通过反射用构造函数动态生成对象
        /// </summary>
        private void CreatObjectByConstruct()
        {
            Type type = reflectionTest.GetType();
            Type[] typeArray = { typeof(string), typeof(string), typeof(string) };
            //根据构造函数参数类型来获取构造函数
            ConstructorInfo constructorInfo = type.GetConstructor(typeArray);
            //要传入的参数
            object[] objectArray = { "王二", "蘑菇", "8cm" };
            //调用构造函数来生成对象
            object obj = constructorInfo.Invoke(objectArray);
            //调用打印方法,看是否有输出
            ((ReflectionTest)obj).ShowContent();
        }
    
        /// <summary>
        /// 通过反射用Activator静态生成对象
        /// </summary>
        private void CreatObjByActivator()
        {
            Type type = reflectionTest.GetType();
            object[] objects = { "张三", "阿姆斯特朗回旋炮", "22cm" };
            object obj = Activator.CreateInstance(type, objects);
            //调用打印方法,看是否有输出
            ((ReflectionTest)obj).ShowContent();
        }
    
        /// <summary>
        /// 通过反射,创建对象,给字段,属性赋值,调用方法
        /// </summary>
        private void CreatAndSet()
        {
            Type type = reflectionTest.GetType();
            //创建对象
            object obj = Activator.CreateInstance(type);
            //通过名字获取字段
            FieldInfo fieldInfo = type.GetField("ranking");
            //给字段赋值
            fieldInfo.SetValue(obj, 1);
            //获取所有属性的信息
            PropertyInfo[] propertyInfos = type.GetProperties();
            string[] strings = { "李四", "阿姆斯特朗回旋炮", "33cm" };
            //依次给属性属性赋值
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                propertyInfos[i].SetValue(obj, strings[i], null);
            }
            //根据名字找到方法的信息
            MethodInfo methodInfo = type.GetMethod("StartMove");
            //执行方法
            methodInfo.Invoke(obj, null);
            //根据名字找到方法的信息
            MethodInfo methodInfo2 = type.GetMethod("ShowRanking");
            //执行方法
            methodInfo2.Invoke(obj, null);
        }
    
    }
    
    1.System.Type类

    System.Type类定义了很多成员,可以用来检查某个类型的元数据,它们返回的类型大多位于System.Reflection命名空间中。举例来说,Type.GetMethods()返回一个MethodInfo类型的数组,Type.GetFields返回一个FieldInfo类型的数组等。System.Type提供的完整的成员组是很容易扩展的。

    2.使用System.Object.GetType()得到Type引用

    可以用多种方法得到一个Type类的实例。但是,由于Type是一个抽象类,所以不能直接使用new关键字创建一个Type对象。对此我们的首选是:使用System.Object定义的GetType()方法,它返回一个表示当前对象元数据的Type类的实例:

    //使用一个SportsCar实例得到类型信息
    SportsCar sc = new SportsCar();
    Type t = sc.GetType();
    

    显而易见,要想使用这个方法,必须得到类型的编译时信息(这里是SportsCar类),并且当前在内存中类型实例。

    GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法

    3.使用typeof()得到Type引用

    另一个取类型信息的方法是使用C# typeof操作符:

    //使用typeof得到类型
    Type t = typeof(SportsCar);
    

    类似System.Object.GetType(),使用typeof操作符,我们不需要建立一个实例来提取类型信息。但是,仍然需要知道类型的编译时信息,因为typeof需要的是类型的强类型名称,而不是文本表示。

    4.使用System.Type.GetType()得到Type引用
    image.png

    为了以更灵活的方式得到类型信息,我们可以调用System.Type类的静态成员GetType(),然后指定类型的完全限定名。采用这种方法,我们不需要得到正从中提取元数据的类型的编译时信息,

    1)Type.GetType()方法被重载一:
    允许我们指定两个布尔类型的参数,一个用来控制当类型找不到时是否抛出异常,另一个用来指示是否区分字符串大小写。例如:

    //使用静态的Type.GetType()方法获取类型信息(如果SportsCar没有找到,则忽略不抛出异常信息)
    Type t = Type.GetType("CarLibrary.SportsCar",false,true);
    

    2)Type.GetType()方法被重载二:

    在上面的例子中,注意传入GetType()的字符串没有包含类型所在的程序集信息。在这种情况下,该类型便被认为是定义在当前执行的程序集中。但是,当希望得到一个外部私有程序集的类型元数据时,字符串参数必须使用类型完全限定名,加上类型所在的程序集的名字(每一个都用逗号隔开):

    //得到外部程序集中类型的类型信息
    Type t= Type.GetType("CarLibrary.SportsCar,CarLibrary");
    
    二、常见用处

    参考对c# 反射使用的一些整理

    1.判断一个对象里面 所有属性的值是否都为true
    public class Temp
    {
        public bool CalculationCompleted{get;set;}
        public bool CollectionCompleted{get;set;}
        public bool ConfigCompleted{get;set;}
        public bool ExecCompleted{get;set;}
    }
    

    常见的写法可能是这样

    Temp t=new Temp();
    if(t.CalculationCompleted&&t.CollectionCompleted&&t.ConfigCompleted&&t.ExecCompleted)
    {
        Console.WriteLine("所有属性值都为True");
    }
    

    这样子写没有毛病, 但是如果要判断的属性变多了呢,比如几十个,那么用这种方法写显而易见,代码量很大,而且只要Temp的属性增加了,就需要重新修改if判断,很不灵活。下面换一种写法:

     public static bool IsAllCompleted<T>(T obj)
     {
        if (obj == null)
        {
            return false;
        }
        Type t = typeof(T);
        //获取属性的集合
        PropertyInfo[] properties = t.GetProperties();
        foreach (var p in properties)
        {
            if (p.Name.Contains("Completed"))
            {
            //获取属性值
                bool isCollectionCompleted = (bool)p.GetValue(obj, null);
                if (!isCollectionCompleted)
                {
                     //只要有一个数据为false就直接返回
                     return false;
                }
            }
        }
        return true;
     }
     
    Temp t=new Temp();
    if(IsAllCompleted<Temp>(t))
    {
        Console.WriteLine("所有属性值都为True");
    }
    

    这种写法通过反射获取对象中所有属性,并获取值,然后循环判断值是否为false,显而易见,通过反射不需要管类中有多少个属性,不管是新增的属性还是删除的属性 ,只需要一个循环就可以得到所有属性的值,可以说非常灵活。

    2.动态生成Sql

    下面写一个我们经常写的Sql语句 Insert into Temp(CalculationCompleted,CollectionCompleted,ConfigCompleted,ExecCompleted) Values(@CalculationCompleted,@CollectionCompleted,@ConfigCompleted,@ExecCompleted)

    这是一个参数化的插入Sql,如果表字段比较少,那这么写还好,但是如果很多,而且表字段不固定,那么这么写就不灵活了。下面通过运用反射来动态生成Sql,首先需要这个表的实体类,我们还用这个吧

    public class Temp
    {
        public bool CalculationCompleted{get;set;}
        public bool CollectionCompleted{get;set;}
        public bool ConfigCompleted{get;set;}
        public bool ExecCompleted{get;set;}
    }
    

    封装两个方法

    /// <summary>
    /// 返回属性名称(name,name,name)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public string GetParas<T>()
    {
        StringBuilder columns = new StringBuilder();
        Type t = typeof(T);
        PropertyInfo[] properties = t.GetProperties();
        foreach (var p in properties)
        {
            if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST"))
            {
                continue;
            }
            columns.Append(p.Name).Append(",");
        }
        return columns.Remove(columns.Length - 1, 1).ToString();
    }
    
    /// <summary>
    /// 返回属性名称(@name,@name,@name)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public string GetATParas<T>()
    {
        StringBuilder columns = new StringBuilder();
        Type t = typeof(T);
        PropertyInfo[] properties = t.GetProperties();
        foreach (var p in properties)
        {
            if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST"))
            {
                continue;
            }
            columns.Append("@").Append(p.Name).Append(",");
        }
        return columns.Remove(columns.Length - 1, 1).ToString();
    }
    

    调用方法

    string para=GetParas<Temp>();
    string atPara=GetATParas<Temp>();
     
    Insert into Temp(para) Values(atPara)
    

    这样写,如果Temp表中新增的字段,那么只要实体类重新生成一下就可以了,sql语句完全不需要修改。

    3.动态调用类中的方法

    先创建一个类

    public class Temp
    {
        public bool CalculationCompleted{get;set;}
        public bool CollectionCompleted{get;set;}
        public bool ConfigCompleted{get;set;}
        public bool ExecCompleted{get;set;}
        
        public bool Calculation(DateTime time)
        {
            return true;
        }
        
        public bool Collection(DateTime time)
        {
            return true;
        }
        
        public bool Config(DateTime time)
        {
            return true;
        }
        
        public bool Exec(DateTime time)
        {
            return true;
        }
    }
    

    常见的调用类方法

    Temp t=new Temp();
    DateTime time=new DateTime();
    t.CalculationCompleted=t.Calculation(time);
    t.CollectionCompleted=t.Collection(time);
    t.ConfigCompleted=t.Config(time);
    t.ExecCompleted=t.Exec(time);
    

    这样子明显很不灵活。如果类成员属性、方法增加就需要在重新写N条t.XXXCompleted=t.XXX(time),反射执行类方法

    public static void ReflectExecMethod<T>(T obj)
    {
        string strReslutMsg = string.Empty;
        decimal reslutMoney = 0;
        Type t = typeof(T);
        PropertyInfo[] properties = t.GetProperties();
        foreach (var p in properties)
        {
    
            //获取属性值
            bool isCollectionCompleted = (bool)p.GetValue(obj, null);
            //判断属性值是否为false,如果是则执行方法
            if (!isCollectionCompleted)
            {
                //方法需要的参数集合
                object[] args = new object[] { DateTime.Now };
                //获取方法名
                string strMethodName = p.Name.Split(new string[] { "Completed" }, StringSplitOptions.RemoveEmptyEntries)[0];
                //执行方法得到结果
                bool result = (bool)t.GetMethod(strMethodName).Invoke(obj, args);
                //赋值
                p.SetValue(obj, result, null);
            }
        }
    

    调用

    ReflectExecMethod<Temp>(t)
    

    通过反射调用类成员方法,并赋值 。。这样子写的好处,如果类成员方法、成员属性后面在增加了,主要符合规则,上面的代码就不需要修改。

    4.行转列

    创建一个最终生成表格的实体类

    public class TempRowToColumn
    {
        //类目
        public string Category{get;set;}
        
        //查了几天 这里就要写几个属性
        public stirng  Time1{get;set;}
        public stirng  Time2{get;set;}
        public stirng  Time3{get;set;}
        public stirng  Time4{get;set;}
        public stirng  Time5{get;set;}
    }
    
    image.png

    我们的实体类

    public class Temp
    {
        public bool CalculationCompleted{get;set;}
        public bool CollectionCompleted{get;set;}
        public bool ConfigCompleted{get;set;}
        public bool ExecCompleted{get;set;}
    }
    

    查询出的列表


    image.png

    很明显我们列表的列变成了表格的行,下面我们用反射完成行转列的操作

    //创建一个存储最终生成表格的List
    List<TempRowToColumn> tempRowToColumnList=new List<TempRowToColumn>();
    //先把要显示的所有列存进去
    TempRowToColumn t=new TempRowToColumn();
    t.Category="计算是否完成";
    tempRowToColumnList.add(t);
     
    TempRowToColumn t=new TempRowToColumn();
    t.Category="采集是否完成";
    tempRowToColumnList.add(t);
     
    TempRowToColumn t=new TempRowToColumn();
    t.Category="配置是否完成";
    tempRowToColumnList.add(t);
     
    TempRowToColumn t=new TempRowToColumn();
    t.Category="执行是否完成";
    tempRowToColumnList.add(t);
     
    //创建一个存储未进行行转列的集合  
    List<Temp> tempList=new List<Temp>();
    //存储5天的数据
    for(int i=0;i<5;i++)
    {
        Temp t=new Temp();
        t.CalculationCompleted=true;
        t.CollectionCompleted=true;
        t.ConfigCompleted=true;
        t.ExecCompleted=true;
        t.DateTime=DateTime.Now.AddDate(i);
        tempList.add(t);
    }
     
    tempRowToColumnList.ForEach(g=>{
        
        //因为TempRowToColumn类第一个属性为类目 所有从所有1开始
        int i=1;
        //反射获取属性列表
        System.Reflection.PropertyInfo[] proInfoArray = g.GetType().GetProperties();
        //行转列后 列为时间,所有这里要循环时间
        for (DateTime j = tempList.Min(t=>t.DateTime); j <= tempList.Max(t=>t.DateTime); j = j.AddDays(1)) 
        {
            //查找出当前循环到日期的一条数据
            Temp tt=tempList.find(t=>t.DateTime.CompareTo(j)==0);
            bool value=false;
            switch(g.Category)
            {
                case "计算是否完成":value=tt.CalculationCompleted;
                    break;
                case "采集是否完成":value=tt.CollectionCompleted;
                    break;
                case "配置是否完成":value=tt.ConfigCompleted;
                    break;
                case "执行是否完成":value=tt.ExecCompleted;
                    break;  
                default:value=false;
                    break;
            }
            string strValue=value??"是":"否";
            proInfoArray[i].SetValue(g,strValue,null);
            i++;
        }
    })
    

    执行结束后 tempRowToColumnList就是行转列后的结果集。

    相关文章

      网友评论

          本文标题:C# 反射 typeof GetType

          本文链接:https://www.haomeiwen.com/subject/bcjdtrtx.html