美文网首页
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

    一、typeof GetType 参考Unity C# 游戏开发 反射 Reflection 案例讲解(图文详细,...

  • C# GetType和typeof

    C#GetType和typeofC#中的所有类型都在运行时由System.Type的实例表示。 有两种基本方法来获...

  • 记录 typeof 和 GetType()

    基本用法:都是为了获取某个实例引用的数据类型 System.Type1.GetType()是先持有一个对象,通过....

  • 2021-07-14【c#】typeof 获取子类类型

    使用GetType替代typeof 这不是我想要的。我想在父类中调用就获得子类的类型。

  • GO: reflect包

    在 reflect 包中,主要通过两个函数 TypeOf() 和 ValueOf() 实现反射,TypeOf() ...

  • Golang学习 - reflect 包(待看)

    在 reflect 包中,主要通过两个函数 TypeOf() 和 ValueOf() 实现反射,TypeOf() ...

  • C#它山之石

    C# 使用反射技术实例化指定的类C#之玩转反射Reactive Extensions入门IoC solutions...

  • Unity 之如何写出强壮的代码

    【反射】 Unity C#基础之 反射反射,程序员的快乐 Unity C#基础之 特性,一个灵活的小工具 【多线程...

  • Unity 通过Type来new对象

    在c#里可以通过Type来获得对应的类型。例如 int a = 4;a.GetType(); 就可以得到一个int...

  • 目录 - C#

    总目录 C# 第01局:泛型 C# 第02局:反射 C# 第03局:特性 C# 第04局:委托 C# 第05局:事...

网友评论

      本文标题:C# 反射 typeof GetType

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