Mag*_*nus 73 c# reflection properties getproperties
我需要按照在类中声明它们的顺序使用反射来获取所有属性.根据MSDN,使用时无法保证订单GetProperties()
GetProperties方法不以特定顺序返回属性,例如按字母顺序或声明顺序.
但我已经读过,通过订购属性有一个解决方法MetadataToken
.所以我的问题是,这样安全吗?我似乎无法在MSDN上找到有关它的任何信息.或者有没有其他方法来解决这个问题?
我目前的实施情况如下:
var props = typeof(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.OrderBy(x => x.MetadataToken);
Run Code Online (Sandbox Code Playgroud)
gho*_*ord 132
在.net 4.5 (甚至vs2012中的.net 4.0)中,您可以使用带有[CallerLineNumber]
属性的聪明技巧进行反射,让编译器为您的属性插入顺序:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class OrderAttribute : Attribute
{
private readonly int order_;
public OrderAttribute([CallerLineNumber]int order = 0)
{
order_ = order;
}
public int Order { get { return order_; } }
}
public class Test
{
//This sets order_ field to current line number
[Order]
public int Property2 { get; set; }
//This sets order_ field to current line number
[Order]
public int Property1 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后使用反射:
var properties = from property in typeof(Test).GetProperties()
where Attribute.IsDefined(property, typeof(OrderAttribute))
orderby ((OrderAttribute)property
.GetCustomAttributes(typeof(OrderAttribute), false)
.Single()).Order
select property;
foreach (var property in properties)
{
//
}
Run Code Online (Sandbox Code Playgroud)
如果必须处理部分类,则可以使用以下方法对属性进行排序[CallerFilePath]
.
Yah*_*hia 12
根据MSDN MetadataToken
在一个模块中是独一无二的 - 没有任何说明它保证任何订单.
即使它确实按照您希望的方式运行,也可能是特定于实现的,并且可能随时更改,恕不另行通知.
请参阅此旧版MSDN博客文章.
我强烈建议远离对此类实现细节的依赖 - 请参阅Marc Gravell的回答.
如果你在编译时需要一些东西,你可以看看Roslyn(虽然它处于一个非常早期的阶段).
Chr*_*ney 12
如果你要去属性路线,这是我过去使用过的方法;
public static IOrderedEnumerable<PropertyInfo> GetSortedProperties<T>()
{
return typeof(T)
.GetProperties()
.OrderBy(p => ((Order)p.GetCustomAttributes(typeof(Order), false)[0]).Order);
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它;
var test = new TestRecord { A = 1, B = 2, C = 3 };
foreach (var prop in GetSortedProperties<TestRecord>())
{
Console.WriteLine(prop.GetValue(test, null));
}
Run Code Online (Sandbox Code Playgroud)
哪里;
class TestRecord
{
[Order(1)]
public int A { get; set; }
[Order(2)]
public int B { get; set; }
[Order(3)]
public int C { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果你在所有属性上没有可比属性的类型上运行它,那么该方法将是barf,所以要小心如何使用它并且它应该足以满足要求.
我已经省略了Order:Attribute的定义,因为在Yahia链接到Marc Gravell的帖子中有一个很好的样本.
另一种可能性是使用该System.ComponentModel.DataAnnotations.DisplayAttribute
Order
财产。由于它是内置的,因此无需创建新的特定属性。
然后选择这样的有序属性
const int defaultOrder = 10000;
var properties = type.GetProperties().OrderBy(p => p.FirstAttribute<DisplayAttribute>()?.GetOrder() ?? defaultOrder).ToArray();
Run Code Online (Sandbox Code Playgroud)
类可以这样呈现
public class Toto {
[Display(Name = "Identifier", Order = 2)
public int Id { get; set; }
[Display(Name = "Description", Order = 1)
public string Label {get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我测试过的 MetadataToken 排序是有效的。
这里的一些用户声称这在某种程度上不是好的方法/不可靠,但我还没有看到任何证据 - 也许当给定的方法不起作用时,您可以在这里发布一些代码片段?
关于向后兼容性 - 当您现在正在处理 .net 4 / .net 4.5 时 - Microsoft 正在制作 .net 5 或更高版本,因此您几乎可以假设这种排序方法将来不会被破坏。
当然,也许到 2017 年,当您升级到 .net9 时,您会遇到兼容性问题,但到那时,Microsoft 人员可能会弄清楚“官方排序机制”。返回或破坏事物是没有意义的。
为属性排序使用额外的属性也需要时间和实现 - 如果 MetadataToken 排序有效,为什么要打扰?