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

日常开发中,反射可以说是经常用到的东西了,比如 类属性不能写死的 、List行转列的 、执行方法,调用类可配置之类的等等 都会用到反射。

一、动态判断对象属性值

比如说我需要判断一个对象里面 所有属性的值是否都为true

先创建一个类Temp

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,显而易见,通过反射不需要管类中有多少个属性,不管是新增的属性还是删除的属性 ,只需要一个循环就可以得到所有属性的值,可以说非常灵活。


二、动态生成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语句完全不需要修改。

三、动态调用类中的方法

先创建一个类

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)

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

四、行转列

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

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;}
}

表格如下


我们的实体类

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

查询出的列表

很明显我们列表的列变成了表格的行

下面我们用反射完成行转列的操作

//创建一个存储最终生成表格的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就是行转列后的结果集。


结束语:

上面仅仅是反射一部分的日常开发经常用到的使用方法,反射的用处很多,我就不一一写了,请自行开发反射用途大笑

上面的代码都为Notepad++ 手打,所以可能有失误尴尬


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值