• 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

    1. 返回为当前Type的所有公共属性
    2. 在System命名空间下,是Type类的实例方法。

    GetRuntimeProperties

    1. 检索表示指定类型上定义的所有属性的集合。
    2. Type类的扩展方法。
    3. 在System.Reflection命名空间下,是RuntimeReflectionExtensions类的静态方法。

    --------------The  End--------------

    ----------本篇文章到此结束----------

  • 相关阅读:
    webrtc相关介绍
    Q-Learning笔记
    数据库-基础篇-SQL-DML(数据操作语言)
    Vue项目中组件如何使用
    不使用EF框架实现数据库增删改查
    基于Java毕业设计制药企业人力资源管理系统源码+系统+mysql+lw文档+部署软件
    php5.2.17安装8.30以上版本pcre库
    二十一、SpringBoot + Jwt + Vue 权限管理系统 (2)
    Activiti——流程的挂起与激活
    虾皮店铺所有商品数据接口(shopee.item_search_shop)
  • 原文地址:https://www.cnblogs.com/iZOHC/p/16243641.html