C# PropertyInfo详解:获取对象属性及判断默认值的方法
在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 则会被跳过。地址列表中的空项也会相应处理。这有助于精简输出日志或传输数据。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









