C# 随机给一个全部信息都未知的类类型,如何获取该类的类名、属性个数、属性名、属性的数据类型、属性值?
一、场景假设
假设现在有一个泛型类T的实例对象t,该T类的全部信息都未知。
要求:打印输出实例对象t的类名、属性个数、属性名、属性的数据类型、属性值。
二、解决问题
1、根据要求,定义了一个输出实体模型类如下:
/// <summary>
/// 输出实体模型类
/// </summary>
public class GeneralDataModel
{
/// <summary>
/// 类名
/// </summary>
public string class_name { get; set; }
/// <summary>
/// 属性个数
/// </summary>
public int prop_count { get; set; }
/// <summary>
/// 属性信息列表
/// </summary>
public List<PropInfoItem> props { get; set; }
}
/// <summary>
/// 单项属性信息类
/// </summary>
public class PropInfoItem
{
/// <summary>
/// 属性名
/// </summary>
public string prop_name { get; set; }
/// <summary>
/// 属性数据类型
/// </summary>
public string prop_data_type { get; set; }
/// <summary>
/// 属性值
/// </summary>
public string prop_value { get; set; }
}
2、编写一个方法,该方法的主要功能是解析实例对象t,并输出步骤1中格式的内容。方法实现代码如下:
public static GeneralDataModel DataAnalysis<T>(T t)
{
var data_type = t.GetType();
var propInfo = data_type.GetProperties();//注意下GetProperties这个方法
var list = new List<PropInfoItem>();
foreach (var item in propInfo)
{
var e = new PropInfoItem
{
prop_name = item.Name,
prop_data_type = item.PropertyType.Name,
prop_value = item.GetValue(t) == null ? "" : item.GetValue(t).ToString()
};
list.Add(e);
}
var res = new GeneralDataModel
{
class_name = data_type.Name,
prop_count = propInfo.Count(),
props = list
};
return res;
}
三、验证方法功能
1、假设现在有一个学生类(这个类的具体信息你是不知道的)如下所示:
public class Student
{
/// <summary>
/// 学号
/// </summary>
public int no { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string name { get; set; }
/// <summary>
/// 年级
/// </summary>
public string grade { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public DateTime birth { get; set; }
}
2、根据该类实例化了一个st对象如下:
var st = new Student()
{
no = 123456,
name = "张三",
grade = "六年级",
birth = DateTime.Now
};
3、调用DataAnalysis方法解析st,并打印输出结果如下:
var res = DataAnalysis(st);
Console.WriteLine(JsonConvert.SerializeObject(res));
{
"class_name": "Student",
"prop_count": 4,
"props": [
{
"prop_name": "no",
"prop_data_type": "Int32",
"prop_value": "123456"
},
{
"prop_name": "name",
"prop_data_type": "String",
"prop_value": "张三"
},
{
"prop_name": "grade",
"prop_data_type": "String",
"prop_value": "六年级"
},
{
"prop_name": "birth",
"prop_data_type": "DateTime",
"prop_value": "2022/5/7 17:21:12"
}
]
}
4、看到输出结果后,感觉完美的解决了问题。
四、变化无常
1、因为种种原因,学生类增加了两个属性,同时实例化对象的创建形式也变了,变化后的形式如下:
public class Student
{
/// <summary>
/// 无参构造函数
/// </summary>
public Student()
{
}
/// <summary>
/// 有参构造函数
/// </summary>
/// <param name="id_card_no">身份证</param>
/// <param name="address">家庭地址</param>
public Student(string id_card_no, string address)
{
this.id_card_no = id_card_no;
this.address = address;
}
/// <summary>
/// 学号
/// </summary>
public int no { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string name { get; set; }
/// <summary>
/// 年级
/// </summary>
public string grade { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public DateTime birth { get; set; }
/// <summary>
/// 身份证(受保护类型)
///
/// 本次新增的属性字段
/// </summary>
protected string id_card_no { get; set; }
/// <summary>
/// 家庭地址(私有类型)
///
/// 本次新增的属性字段
/// </summary>
private string address { get; set; }
}
var st = new Student("777888202005071111", "家庭地址私有,暂时不方便透露")
{
no = 123456,
name = "张三",
grade = "六年级",
birth = DateTime.Now
};
2、再次调用DataAnalysis方法解析st,并打印输出结果如下:
var res = DataAnalysis(st);
Console.WriteLine(JsonConvert.SerializeObject(res));
{
"class_name": "Student",
"prop_count": 4,
"props": [
{
"prop_name": "no",
"prop_data_type": "Int32",
"prop_value": "123456"
},
{
"prop_name": "name",
"prop_data_type": "String",
"prop_value": "张三"
},
{
"prop_name": "grade",
"prop_data_type": "String",
"prop_value": "六年级"
},
{
"prop_name": "birth",
"prop_data_type": "DateTime",
"prop_value": "2022/5/7 17:40:21"
}
]
}
4、看到输出结果时,咦?怎么似乎好像哪里不对?新增的那两个属性怎么没有被解析并输出呢?
五、反射了解一下?
1、通过种种途径或者查阅其他资料你了解到了反射的相关知识,并找到了一个名为GetRuntimeProperties的方法。
2、修改原先的解析方法代码如下:
public static GeneralDataModel DataAnalysis<T>(T t)
{
var data_type = t.GetType();
var refPropInfo = data_type.GetRuntimeProperties();//这一行代码有点变化
var list = new List<PropInfoItem>();
foreach (var item in refPropInfo)
{
var e = new PropInfoItem
{
prop_name = item.Name,
prop_data_type = item.PropertyType.Name,
prop_value = item.GetValue(t) == null ? "" : item.GetValue(t).ToString()
};
list.Add(e);
}
var res = new GeneralDataModel
{
class_name = data_type.Name,
prop_count = refPropInfo.Count(),
props = list
};
return res;
}
3、再一次调用DataAnalysis方法解析st,并打印输出结果如下:
var res = DataAnalysis(st);
Console.WriteLine(JsonConvert.SerializeObject(res));
{
"class_name": "Student",
"prop_count": 6,
"props": [
{
"prop_name": "no",
"prop_data_type": "Int32",
"prop_value": "123456"
},
{
"prop_name": "name",
"prop_data_type": "String",
"prop_value": "张三"
},
{
"prop_name": "grade",
"prop_data_type": "String",
"prop_value": "六年级"
},
{
"prop_name": "birth",
"prop_data_type": "DateTime",
"prop_value": "2022/5/7 17:52:12"
},
//这两项信息被成功打印输出
{
"prop_name": "id_card_no",
"prop_data_type": "String",
"prop_value": "777888202005071111"
},
{
"prop_name": "address",
"prop_data_type": "String",
"prop_value": "家庭地址暂时不方便透露"
}
]
}
5、看到这输出结果,脸上露出了满意的笑容,啊~~~问题终于解决了,开森^_^
六、前后对比并溯源
1、方法前后变化仅仅只有一处,由GetProperties
变为了GetRuntimeProperties
。
2、溯源发现如下信息:
GetProperties:
- 返回为当前Type的所有公共属性。
- 在System命名空间下,是Type类的实例方法。
GetRuntimeProperties:
- 检索表示指定类型上定义的所有属性的集合。
- Type类的扩展方法。
- 在System.Reflection命名空间下,是RuntimeReflectionExtensions类的静态方法。
--------------The End--------------
----------本篇文章到此结束----------