应优先用 typeof(T).GetProperties(),仅当需支持 ICustomTypeDescriptor、设计器集成或运行时动态属性注入时才用 TypeDescriptor.GetProperties()。

TypeDescriptor 不是泛用反射替代品,它专为设计时/可扩展元数据场景而生;直接用 typeof(T).GetProperties() 更快、更安全,除非你明确需要自定义类型描述、设计器集成或运行时动态属性注入。
什么时候该用 TypeDescriptor.GetProperties 而不是 Reflection
核心判断标准:你的对象是否可能被 ICustomTypeDescriptor、ISite 或扩展提供者(如 IExtenderProvider)动态修改其公开的属性集?
- WinForms / WPF 设计器中拖放控件后修改
BackColor、Text等属性 → 必须用TypeDescriptor.GetProperties(control),否则拿不到设计器注入的 shadow 属性 - 业务实体类实现了
ICustomTypeDescriptor,并在GetProperties中按用户权限返回不同字段 → 只有TypeDescriptor能触发该逻辑 - 你只是想遍历一个 POCO 的 public 属性做序列化 → 别用它,
type.GetProperties(BindingFlags.Public | BindingFlags.Instance)更直白、无缓存副作用、不触发RequiresUnreferencedCode警告 - 调用
TypeDescriptor.GetProperties(obj)后修改了对象状态(比如调用了Refresh),但后续仍读旧缓存 → 记得手动调TypeDescriptor.Refresh(obj)
TypeDescriptor.AddAttributes 动态加特性,但只对 TypeDescriptor.GetAttributes 有效
它不能改变 Attribute.GetCustomAttribute 的结果,也不能影响 JIT 编译或运行时行为 —— 它只改 TypeDescriptor 自己的缓存视图。
- 适用场景:给某个具体对象实例临时打标(比如标记“此 DataGridViewRow 当前处于编辑态”),且下游代码明确用
TypeDescriptor.GetAttributes(row)检查 - 不生效的情况:
[MyValidator] class Person { ... }上加的 attribute,用TypeDescriptor.AddAttributes(person, new MyValidator())不会触发MyValidator的验证逻辑 - 注意参数顺序:
TypeDescriptor.AddAttributes(object instance, params Attribute[] attrs),第一个参数必须是**实例**,传Type会静默失败 - 添加后立即读取需用同签名的
TypeDescriptor.GetAttributes(instance),用instance.GetType().GetCustomAttributes()看不到
TypeDescriptor.GetClassName 返回的是“设计时名称”,不是 GetType().FullName
它可能被 ICustomTypeDescriptor 或组件 Site 替换,尤其在设计器宿主环境里常见。
- 普通对象(无定制):返回
obj.GetType().FullName,例如"System.String" - WinForms
Button实例:设计时可能返回"Button"(短名),而非完整命名空间 - 若对象实现了
ICustomTypeDescriptor并重写GetClassName()→ 返回值完全由你控制,和真实类型无关 - 传
null会抛ArgumentNullException,不是返回null或空字符串 - 在 AOT 编译(如 .NET Native 或 trimming 启用时)下,该方法带
RequiresUnreferencedCode属性,可能被 trim 掉 —— 若你依赖它生成 UI 标签,需在.csproj中保留相关类型
TypeDescriptor.GetEditor 和设计器强绑定,运行时几乎没用
它本质是查找 [Editor(...)] 特性指定的类型,并尝试创建其实例。但这个过程严重依赖设计时上下文(IDesignerHost、IServiceContainer)。
- 在 WinForms 设计器中双击属性打开编辑器 → 底层就是调
TypeDescriptor.GetEditor(propValue, typeof(UITypeEditor)) - 在纯控制台程序里调用它,大概率返回
null,因为缺ITypeDescriptorFilterService等服务支持 - 即使拿到 editor 实例,
editor.EditValue(...)通常需要 Win32 窗口句柄或IWindowsFormsEditorService,无法在无 UI 线程安全调用 - 不要试图用它做运行时“弹窗选值”——改用 MVVM + DialogService 或直接 new Editor 类型
真正容易被忽略的点:所有 TypeDescriptor 方法都走内部静态缓存,且缓存键基于对象引用(不是类型)。同一个对象多次调用 GetProperties 得到的是同一 PropertyDescriptorCollection 实例 —— 如果你把它存起来长期复用,要注意它可能已被其他代码通过 Refresh 或扩展提供者悄悄更新了结构。


















