一、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");
二、常见用处
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就是行转列后的结果集。
网友评论