跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

C#如何反射获取类的属性_C#动态创建对象实例【进阶】

GetProperties()返回空数组主因是BindingFlags未配对;默认仅返回public实例属性,需显式添加NonPublic、Static、FlattenHierarchy等标志;泛型类反射须用MakeGenericType构造封闭类型,继承属性需手动遍历基类。 GetProperties() 返回空数组的常见原因 反射拿不到属性,大概率不是代码写错,而是访问级别或泛型/继承干扰导致。默认
GetProperties()
只返回
public
实例属性,且不递归基类——哪怕你写了
virtual
或
override
,父类的
public
属性也不会自动出现。 要包含非 public 属性(如
private
、
protected
),必须显式传入
BindingFlags
:
typeof(MyClass).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
要包含基类属性,得手动向上遍历:
type.BaseType?.GetProperties(...)
,.NET 没有内置“全继承链属性”快捷方法 泛型类实例(如
MyClass
)反射时要用
typeof(MyClass<>)
获取泛型定义,再调用
MakeGenericType(...)
构造封闭类型,否则
GetProperties()
会失败或返回空 Activator.CreateInstance() 创建泛型实例的坑 直接传泛型类型参数给
Activator.CreateInstance()
很容易报
ArgumentException: Type must be a runtime type
,因为没区分开放泛型和封闭泛型。 开放泛型类型(如
typeof(List<>)
)不能直接实例化,必须先构造封闭类型:
typeof(List<>).MakeGenericType(typeof(int))
带构造参数的泛型类(如
class Repo { public Repo(IOptions opts) {...} }
),不能靠
Activator.CreateInstance(type, args)
自动解析依赖,它不走 DI 容器逻辑——此时应改用
IServiceProvider.GetService(type)
性能敏感场景慎用
Activator.CreateInstance()
:它比直接 new 慢 5–10 倍。高频创建建议缓存
ConstructorInfo.Invoke()
或预编译表达式树 PropertyInfo.SetValue() 报 TargetException 的真实含义
TargetException
并不表示属性不存在,而是目标对象与属性所属类型不匹配——比如你用
obj.GetType().GetProperty("Name")
拿到的是
Person.Name
的
PropertyInfo
,却试图对一个
Employee
实例(虽继承自
Person
)调用
SetValue()
,而该属性在
Employee
中被重写为
new
字段,则会失败。 C知道 CSDN推出的一款AI技术问答工具 下载 检查属性是否是
virtual
且被
override
:此时应通过
obj.GetType().GetProperty("Name")
(而非基类类型)获取,确保类型一致 值类型属性赋值时注意装箱:对
int
属性设
null
会抛异常,需先判断
property.PropertyType.IsNullable()
(辅助方法需自行实现) 只读属性(只有
get
)调用
SetValue()
会静默失败(不报错但无效果),可用
property.CanWrite
提前校验 动态创建对象后如何安全绑定 JSON 数据 用反射创建实例后接
System.Text.Json
反序列化,常因属性名大小写、忽略只读字段等策略不一致导致绑定失败。 不要用
JsonSerializer.Deserialize(json) ——它不会还原为你的目标类型,而是变成
JsonElement
或
Dictionary
正确做法是:先用
Activator.CreateInstance(targetType)
创建空实例,再用
JsonSerializer.Populate()
注入数据(需启用
PropertyNameCaseInsensitive = true
) 若目标类含
[JsonIgnore]
或
[JsonPropertyName("xxx")]
,
Populate()
默认不识别这些特性,得传入自定义
JsonSerializerOptions
并设置
IgnoreReadOnlyProperties = false
等选项 反射链越长(类型推导 → 属性遍历 → 值设置 → 序列化注入),出问题的位置就越隐蔽。别依赖“看起来能跑”,每个环节都要验证
PropertyInfo
是否来自预期类型、
CanWrite
是否为 true、
IsAssignableFrom()
是否成立——这些检查加起来不到三行,却能省掉半天调试时间。

相关文章