31

How can I get a Types FieldInfos/PropertyInfos as a MemberInfo array in the order they are laid out in the class?

class Test
{
    public bool First { get; set; }
    public int Second;
    public string Third { get; set; }
}
Will
  • 10,013
  • 9
  • 45
  • 77

5 Answers5

32

http://msdn.microsoft.com/en-us/library/ch9714z3.aspx

The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which fields are returned, because that order varies.

http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies.

You would need to define order yourself, perhaps with attributes:

class Test
{
    [Order(1)] public bool First { get; set; }
    [Order(2)] public int Second;
    [Order(3)] public string Third { get; set; }
}
...
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, 
    Inherited = true, AllowMultiple = false)]
[ImmutableObject(true)]
public sealed class OrderAttribute : Attribute {
    private readonly int order;
    public int Order { get { return order; } }
    public OrderAttribute(int order) {this.order = order;}
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 3
    So do you perchance know how the XmlSerializer does get the order? Is that framework internal? – H.B. Mar 29 '11 at 13:50
  • 1
    @H.B. if it mattered, I would specify the order explicitly in `[XmlElement]`, but to answer your question: no – Marc Gravell Mar 29 '11 at 13:59
  • Happen to know if the order varies between runs or just builds? Like I am assuming it varies because of optimizations when you add/remove fields/properties from the class. – Will Mar 29 '11 at 14:38
  • @High - I *suspect* it won't change between either; however, it could easily change between compilers, or if you refactor. It is, basically, undefined behaviour: ***anything*** is valid (within reason). – Marc Gravell Mar 29 '11 at 16:09
  • Someone just suggested ordering by MetadataToken. What are your thoughts on that? – Will Mar 29 '11 at 16:45
  • 3
    @High my thoughts are: do you know exactly how it behaves between builds? Is it stable? Is it guaranteed? Or *if* it works, is it by chance, that could change in 2 builds time, or when you change .NET service-pack, or CPU architecture? – Marc Gravell Mar 29 '11 at 16:58
  • I agree this is a valid question (and one I have myself). Ignoring the XmlSerializer, where ordering isn't respected (and doesn't need to be), this is valid for marshaling where it is and does. – Jeff Dec 21 '11 at 22:05
  • @Jeff for marshallying, you're probably looking at `LayoutKind.Explicit` and `[FieldOffset(n)]` – Marc Gravell Dec 21 '11 at 22:07
  • 2
    What about LayoutKind.Sequential? This suggests there is information somewhere about the declaration ordering. – Jeff Dec 21 '11 at 22:14
  • 2
    @Jeff well, in part; not completely; in particular, I cite 10.2.6 from the spec: 10.2.6 Members [...] The ordering of members within a type is rarely significant to C# code, but may be significant when interfacing with other languages and environments. In these cases, **the ordering of members within a type declared in multiple parts is undefined**. (emphasis mine) – Marc Gravell Dec 21 '11 at 22:20
4

Look at Mono.Cecil

If the Serializer is able to do source ordering it won't be because of the PDB debug info.

I assume reflection loses the ordering because it will (potentially) return a mix of direct and inherited members. There is no 'correct' ordering of that mix.

Mono.Cecil will let you get directly at the structures in the managed assembly, as well as at the CIL code. Mono.cecil rocks big time and will not eat your puppies. It is the fastestest method to analyze your assemblies, and you don't even have to have them loaded.

Mono.Cecil goes on to write a new assembly if you wish, but this propaganda is getting way off-topic.

Go get Mono.Cecil

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 2
    Debunking a potential myth: you don't need mono to use Cecil. Just download the single assembly, reference it (in VS e.g.) and you're done – sehe Mar 29 '11 at 15:08
  • 1
    Heh, thanks for the propaganda, but it won't solve completely the issue. Cecil can't tell you the order in which the property, then the field, then the property are sorted in the C# source, are they are of different kind. Plus, the compiler is completely free to emit members in the assembly in a different order from how they are defined in the source. – Jb Evain Mar 29 '11 at 16:20
  • I suppose the issue is with ordering like XMLSerializer does. This should be solvable, isn't it? (Also, nice of you to drop by, ) – sehe Mar 29 '11 at 18:16
  • On that topic, I found that in fact to have reliable ordering (`In .NET 2.0, you can also “explicitly“ control this using the XmlElementAttribute.Order`)[http://www.pluralsight-training.net/community/blogs/tewald/archive/2006/04/18/21964.aspx] and others – sehe Mar 29 '11 at 18:44
3

You can't, as this info is not relevant to the execution or functionality of the class. Why would you want to retrieve this info anyway?

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • 1
    Ar you sure about that? When i serialize an object to XML the order is that of the appearance in the class file. – H.B. Mar 29 '11 at 13:43
  • 1
    @H.B.: Yes, I am sure: ["The GetMembers method does not return members in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which members are returned, because that order varies."](http://msdn.microsoft.com/en-us/library/424c79hc.aspx) – Daniel Hilgarth Mar 29 '11 at 13:45
  • It's not relevant for the use cases reflection was designed for. [sic] That is not conclusive – sehe Mar 29 '11 at 15:06
  • 1
    @H.B: no the xml serializer doesn't preserve the order. If you serialize the Test type, as shown in the question, on .net 4.0, the order of the nodes will be: Second, First, Third. – Jb Evain Mar 29 '11 at 20:47
  • 6
    Yes, but interop services respect field ordering when Layoutkind:Sequential is specified, so I believe the question is valid. – Jeff Dec 21 '11 at 22:03
1

The line number information is not compiled in to the assembly, it is stored in the .PDB file for the use of debugger.
Although technically it may be possible to get the information you are looking from the PDB file, I don't think that will be a good idea either, as the PDB file will not be present in the production environment. Even if it is there there is no guarantee that it is in sync with the DLL.

Nimesh Madhavan
  • 6,290
  • 6
  • 44
  • 55
  • There's not even line informations for members in the .pdb. You only have a IL offset -> sequence point mapping. – Jb Evain Mar 29 '11 at 13:56
1

I have found more information when trying to google the other way around. Like JbEvain pointed out, it is confirmed that there is no way to control the order in which the compiler outputs members in CIL classes. This even pertains to XmlSerializer

A number of interesting posts have posted here:

On that topic, I found that in fact to have reliable ordering (In .NET 2.0, you can also “explicitly“ control this using the XmlElementAttribute.Order)[pluralsight-training.net/community/blogs/tewald/archive/2006/04/… and others

This should give a good background to this discussion. It now really depends on what the original poster needed this information for whether there can even be a solution, and if so, to find a route to achieving that goal.

sehe
  • 374,641
  • 47
  • 450
  • 633