C# PropertyInfo详解:获取对象属性及判断默认值的方法

何川
何川
发布时间:2026-10-16 | 3人浏览过
原创

在C#开发中,反射技术常用于对象序列化和动态分析。本文将演示如何利用 System.Reflection.PropertyInfo 类遍历对象的公共属性,并根据属性的数据类型(如时间型、整型)正确识别其默认值状态,从而区分已赋值与未赋值的字段。

核心功能说明

PropertyInfo 类提供了访问属性元数据的功能。通过 Type.GetProperties() 方法,我们可以获取一个类的所有公共属性。在实际业务中,我们经常需要过滤掉那些未被修改的默认值(例如 int 为 0,DateTime 为 1970/1/1),以便生成差异化的JSON或日志信息。

完整代码示例

以下代码定义了一个包含基础类型和集合类型的模型类 People,以及一个核心的反射处理方法 GetValidPropertyValues。该方法会过滤掉无效的默认值。

public class People
{
    public string name { get; set; }
    public int age { get; set; }
    public DateTime birthday { get; set; }
    public bool isActive { get; set; }
    public List<Address> address { get; set; }
}

public class Address
{
    public string country { get; set; }
    public string province { get; set; }
    public string city { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // 构造测试数据,address数组中有两条记录,第一条全填,第二条仅填country/city
        List<Address> addressList = new List<Address>
        {
            new Address { country = "china", province = "anHui", city = "bengBu" },
            new Address { country = "china", city = "shangHai" } // province默认为空串
        };

        var people = new People()
        {
            name = "wangqilong",
            age = 23,
            birthday = Convert.ToDateTime("2018-09-15"),
            isActive = true,
            address = addressList
        };

        // 调用反射处理方法
        string resultStr = GetValidPropertyValues(people);
        Console.WriteLine(resultStr);
    }

    /// <summary>
    /// 遍历属性,过滤掉未初始化的默认值
    /// </summary>
    public static string GetValidPropertyValues(object obj)
    {
        if (obj == null) return string.Empty;

        Type type = obj.GetType();
        PropertyInfo[] properties = type.GetProperties(); // 获取所有公共属性
        StringBuilder sb = new StringBuilder();

        foreach (PropertyInfo p in properties)
        {
            object value = p.GetValue(obj, null);
            
            // 特殊处理:排除集合为null的情况
            if (value is IEnumerable list && !(value is string))
            {
                // 对于集合类型,如果为null则不处理,非null但Count=0也可根据需求过滤
                if (list != null)
                {
                    ProcessCollection(sb, p.Name, value);
                }
                continue;
            }

            // 针对常见类型进行默认值判断
            if (p.PropertyType == typeof(DateTime))
            {
                DateTime dateVal = (DateTime)value;
                // DateTime 默认值为 DateTime.MinValue
                if (dateVal != DateTime.MinValue)
                {
                    sb.Append($"{p.Name}:{dateVal};");
                }
            }
            else if (p.PropertyType == typeof(int))
            {
                int intVal = (int)value;
                // int 默认值为 0
                if (intVal != 0)
                {
                    sb.Append($"{p.Name}:{intVal};");
                }
            }
            else if (p.PropertyType == typeof(bool))
            {
                bool boolVal = (bool)value;
                // bool 默认为 false,通常 false 是有意义的,这里视需求保留
                // 此处演示保留所有 boolean 值,如需排除 false 可在此增加判断
                sb.Append($"{p.Name}:{boolVal};");
            }
            else if (p.PropertyType == typeof(string))
            {
                // string 默认值为 null 或空字符串,可根据需要过滤 null
                if (value != null)
                {
                    sb.Append($"{p.Name}:{value};");
                }
            }
        }

        return sb.ToString();
    }

    private static void ProcessCollection(StringBuilder sb, string propertyName, object collectionObj)
    {
        IEnumerable enumerable = collectionObj as IEnumerable;
        foreach (var item in enumerable)
        {
            // 简单扁平化处理,实际场景可能需要递归深入或格式化输出
            sb.Append($"{propertyName}:{item};");
        }
    }
}

关键知识点解析

第1步:获取对象类型与属性列表

入口位于 Type.GetProperties()。此方法返回当前类的 PropertyInfo 对象数组,涵盖了所有继承下来的公共只读、读写属性。

第2步:区分数据类型

不同的值类型在声明时拥有不同的“空”标志:

  • DateTime:默认值为 DateTime.MinValue(即 0001/1/1)。检查时必须与该值比对,而非使用 != null。
  • Int32 / Int64:作为结构体,未赋值时为最小值 0。
  • String / Class:引用类型默认值为 null。

第3步:安全获取属性值

使用 p.GetValue(obj, null) 获取值。在转换为具体类型前,应先判断 p.PropertyType.FullName 或使用 Type.IsAssignableFrom 以确保转换的安全性。

结果验证

运行上述代码,控制台输出将仅包含有效的非默认值字段。对于 isActive 虽为默认值 false,但在逻辑判断中通常视为有效状态;而对于 birthday,若保持默认的 MinValue 则会被跳过。地址列表中的空项也会相应处理。这有助于精简输出日志或传输数据。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表