3

C# 随机给一个全部信息都未知的类类型,如何获取该类的类名、属性个数、属性名、属性...

 2 years ago
source link: https://www.cnblogs.com/iZOHC/p/16243641.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、场景假设

假设现在有一个泛型类T的实例对象t,该T类的全部信息都未知。

要求:打印输出实例对象t的类名、属性个数、属性名、属性的数据类型、属性值。

二、解决问题

1、我们根据输出的内容要求定义一个实体类如下:

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

4、输出结果如下:

{
    "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"
        }
    ]
}

5、看到输出结果后,感觉完美的解决了问题。

四、变化无常

1、因为种种原因,学生类增加了两个属性,同时实例化对象的创建形式也变了,变化后的形式如下:

    public class Student
    {
        public Student()
        {

        }

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

3、输出结果如下:

{
    "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));

 4、输出结果如下:

{
    "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:在System命名空间下,是Type类的实例方法。
  • GetRuntimeProperties(Type类的扩展方法):在System.Reflection命名空间下,是RuntimeReflectionExtensions类的静态方法。

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK