如何按声明顺序获取匿名类型的所有属性名称?
获取匿名类型属性声明顺序的可靠方法
首先得明确:C#规范里明确规定了匿名类型的属性顺序与声明顺序完全一致,问题在于常规反射方法(比如Type.GetProperties)的返回顺序没有官方保障,而TypeInfo.DeclaredProperties虽然当前可能返回正确顺序,但同样没有明确的官方承诺,所以得找基于编译器生成规则的可靠方案。
下面是两种经过验证的可靠实现方式:
方法1:利用表达式树的NewExpression成员顺序
编译器在生成匿名类型的表达式时,会严格保留属性的声明顺序,我们可以通过表达式树提取这个顺序:
using System.Linq.Expressions; public static List<string> GetAnonymousPropertyOrder<T>(T anonymousInstance) { // 创建一个返回自身的lambda表达式,其Body是NewExpression类型 var parameter = Expression.Parameter(typeof(T), "x"); var lambda = Expression.Lambda<Func<T, T>>(parameter, parameter); var newExpr = (NewExpression)lambda.Body; // NewExpression.Members的顺序就是匿名类型的属性声明顺序 return newExpr.Members.Select(m => m.Name).ToList(); }
使用示例:
var person = new { Name = "Bob", Age = 28, City = "New York" }; var propertyOrder = GetAnonymousPropertyOrder(person); // propertyOrder会是 ["Name", "Age", "City"]
这个方法的可靠性来源于C#编译器的生成规则——匿名类型的构造表达式(NewExpression)的成员顺序完全匹配声明顺序,这是规范明确要求的,不会随CLR版本变化而改变。
方法2:通过构造函数参数顺序获取
匿名类型只会生成一个构造函数,其参数顺序与属性声明顺序完全一致,且参数名就是属性名,我们可以利用这一点:
public static List<string> GetAnonymousPropertyOrder<T>() { // 匿名类型只有一个构造函数 var constructor = typeof(T).GetConstructors().Single(); // 构造函数参数的顺序就是属性声明顺序,参数名等于属性名 return constructor.GetParameters().Select(p => p.Name).ToList(); }
使用示例:
var person = new { Name = "Bob", Age = 28, City = "New York" }; var propertyOrder = GetAnonymousPropertyOrder<typeof(person)>(); // 或者直接传入实例的类型,强类型方式更可靠
这种方法同样可靠,因为C#规范要求匿名类型的构造函数参数顺序必须匹配属性声明顺序,参数名与属性名一致,这是编译器必须遵守的规则。
为什么不推荐TypeInfo.DeclaredProperties?
虽然在当前的.NET实现中,TypeInfo.DeclaredProperties可能会按声明顺序返回属性,但微软的官方文档从未明确承诺这个顺序的稳定性——反射API的返回顺序通常被定义为“未指定”,未来CLR的反射实现可能会调整这个顺序,所以不能作为可靠依赖。
内容的提问来源于stack exchange,提问作者Stalker
相关产品推荐
相关产品推荐

