精简版
Type.GetProperties它返回的集合的状态的MSDN文档不保证按字母顺序或声明顺序,但运行一个简单的测试表明,它通常以声明顺序返回.您是否知道具体情况不是这种情况?除此之外,建议的替代方案是什么?
详细版本
我意识到Type.GetProperties状态的MSDN文档:
GetProperties方法不以特定顺序返回属性,例如按字母顺序或声明顺序.您的代码不得依赖于返回属性的顺序,因为该顺序会有所不同.
因此无法保证方法返回的集合将以任何特定方式进行排序.根据一些测试,我发现相反的返回属性按照它们在类型中定义的顺序出现.
例:
class Simple
{
public int FieldB { get; set; }
public string FieldA { get; set; }
public byte FieldC { get; set; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Simple Properties:");
foreach (var propInfo in typeof(Simple).GetProperties())
Console.WriteLine("\t{0}", propInfo.Name);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Simple Properties:
FieldB
FieldA
FieldC
Run Code Online (Sandbox Code Playgroud)
一个这样的情况,这只是略有不同的是当有问题的类型的父母也有属性时:
class Parent
{
public int ParentFieldB { get; set; }
public string ParentFieldA { get; set; }
public byte ParentFieldC { get; set; }
}
class Child : Parent
{
public int ChildFieldB { get; set; }
public string ChildFieldA { get; set; }
public byte ChildFieldC { get; set; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Parent Properties:");
foreach (var propInfo in typeof(Parent).GetProperties())
Console.WriteLine("\t{0}", propInfo.Name);
Console.WriteLine("Child Properties:");
foreach (var propInfo in typeof(Child).GetProperties())
Console.WriteLine("\t{0}", propInfo.Name);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Parent Properties:
ParentFieldB
ParentFieldA
ParentFieldC
Child Properties:
ChildFieldB
ChildFieldA
ChildFieldC
ParentFieldB
ParentFieldA
ParentFieldC
Run Code Online (Sandbox Code Playgroud)
这意味着该GetProperties方法在发现属性时从下往上遍历继承链.那很好,可以这样处理.
问题:
一个看似显而易见的解决方案是定义一个自定义属性,该属性指示属性应该出现的顺序(与Order属性上的DataMember属性类似).就像是:
public class PropOrderAttribute : Attribute
{
public int SeqNbr { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后执行如下:
class Simple
{
[PropOrder(SeqNbr = 0)]
public int FieldB { get; set; }
[PropOrder(SeqNbr = 1)]
public string FieldA { get; set; }
[PropOrder(SeqNbr = 2)]
public byte FieldC { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但正如许多人所发现的,如果你的类型有100个属性而你需要在前2个之间添加一个属性,这就成了一个严重的维护问题.
UPDATE
此处显示的示例仅用于演示目的.在我的特定场景中,我使用类定义消息格式,然后遍历类的属性并获取其属性以查看消息中的特定字段应如何解组.消息中字段的顺序很重要,因此我的类中的属性顺序需要很大.
它目前通过迭代返回集合来工作GetProperties,但由于文档声明不建议我想了解为什么以及我有什么其他选项?
Mar*_*ell 14
订单根本无法保证; 该发生的总会发生.
可能发生变化的明显案例:
但是一个更微妙的案例:部分类.如果一个类被拆分为多个文件,则根本不会定义它们的使用顺序.请参阅正式定义的部分类中的"文本顺序"吗?
当然,即使对于单个(非部分)定义也没有定义; p
但想象一下
档案1
partial class Foo {
public int A {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
档案2
partial class Foo {
public int B {get;set:}
}
Run Code Online (Sandbox Code Playgroud)
这里有A和B之间没有正式的声明顺序查看链接后,看它如何趋于发生,虽然.
重新编辑; 最好的办法是分别指定编组信息; 一种常见的方法是使用一个带有数字顺序的自定义属性,然后用它来装饰成员.然后,您可以根据此号码进行订购.protobuf-net做了非常相似的事情,坦率地说,我建议在这里使用现有的序列化库:
[ProtoMember(n)]
public int Foo {get;set;}
Run Code Online (Sandbox Code Playgroud)
其中"n"是整数.特别是在protobuf-net的情况下,还有一个API可以单独指定这些数字,这在类型不在您的直接控制之下时非常有用.
对于它的价值,按MetadataToken排序似乎对我有用。
GetType().GetProperties().OrderBy(x => x.MetadataToken)
Run Code Online (Sandbox Code Playgroud)
原始文章(断开的链接,此处刚刚列出以注明出处):http : //www.sebastienmahe.com/v3/seb.blog/2010/03/08/c-reflection-getproperties-kept-in-declaration-order/
1:
我花了最后一天时间对 MVC 3 项目中的一个问题进行故障排除,这一切都归结为这个特定问题。它基本上依赖于整个会话期间属性顺序相同,但在某些情况下,一些属性交换了位置,从而弄乱了站点。
首先调用代码Type.GetProperties()来定义动态 jqGrid 表中的列名称,在这种情况下,每个page_load. 随后Type.GetProperties()调用该方法是为了填充表的实际数据,在某些罕见的情况下,属性会交换位置并完全搞乱了演示。在某些情况下,站点依赖于分层子网格的其他属性被切换,即您无法再看到子数据,因为 ID 列包含错误数据。换句话说:是的,这肯定会发生。谨防。
2:
如果您需要在整个系统会话中保持一致的顺序,但不需要所有会话的顺序完全相同,那么解决方法非常简单:将PropertyInfo[]您获取的数组Type.GetProperties()作为值存储在网络缓存中或以类型(或类型名称)作为类型(或类型名称)的字典中缓存/字典键。随后,每当您要执行 a 时Type.GetProperties(),请将其替换为HttpRuntime.Cache.Get(Type/Typename)or Dictionary.TryGetValue(Type/Typename, out PropertyInfo[])。这样,您就可以保证始终收到您第一次遇到的订单。
如果您总是需要相同的顺序(即对于所有系统会话),我建议您将上述方法与某种类型的配置机制结合起来,即在 web.config/app.config 中指定顺序,对PropertyInfo[]您获得的数组进行Type.GetProperties()排序指定的顺序,然后将其存储在缓存/静态字典中。
我使用自定义属性自己添加必要的元数据(它与类似REST的服务一起使用,该服务使用并返回CRLF分隔的Key = Value对。
首先,一个自定义属性:
class ParameterOrderAttribute : Attribute
{
public int Order { get; private set; }
public ParameterOrderAttribute(int order)
{
Order = order;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,装饰您的类:
class Response : Message
{
[ParameterOrder(0)]
public int Code { get; set; }
}
class RegionsResponse : Response
{
[ParameterOrder(1)]
public string Regions { get; set; }
}
class HousesResponse : Response
{
public string Houses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
将PropertyInfo转换为可排序的int的便捷方法:
private int PropertyOrder(PropertyInfo propInfo)
{
int output;
var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
return output;
}
Run Code Online (Sandbox Code Playgroud)
更好的是,write作为扩展:
static class PropertyInfoExtensions
{
private static int PropertyOrder(this PropertyInfo propInfo)
{
int output;
var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
return output;
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您现在可以使用以下命令查询Type对象:
var props = from p in type.GetProperties()
where p.CanWrite
orderby p.PropertyOrder() ascending
select p;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9257 次 |
| 最近记录: |