mgravell/fast-member

Option to preserve order of Properties/Fields

Closed this issue · 7 comments

MemberSet orders Properties/Fields by name by default. Would be great to preserve field and properties intermingled but I'm not sure that is possible. This is unfortunate since I was relying on natural order in type for a serialization library and dont want to resort to explicit ordering everywhere. Not sure why sort is necessary but loses this information if necessary can this be optional.

Related is that it would be useful that Base Classes could be returned first.

My partial code solution:

members = EnumerateMembers(type).Select(member => new Member(member)).ToArray();

		private static IEnumerable<MemberInfo> EnumerateMembers(Type type)
	    {
		    if (type.BaseType != null)
			    foreach (var props in EnumerateMembers(type.BaseType))
				    yield return props;
		    const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
		    foreach (var pi in type.GetProperties(PublicInstance))
			    yield return pi;
		    foreach (var fi in type.GetFields(PublicInstance))
			    yield return fi;
	    }

Hi @mgravell,

First of all - thanks for the great library! We use it quite broadly.
Is this possible to add special attributes that can be used for defining column order?
Like [ColumnOrdinal(1)]. The properties which don't have this attribute will have ordinal value according to their alphabetical order. If an ordinal turned out to be equal for several properties - we sort them in alphabetical order. How difficult it would be to implement?
We are using this library for streaming CSV files to a Hadoop cluster and adding new columns in the end is critical (Hadoop doesn't support adding columns in the middle - we can add in the end only). As a workaround we name new columns like XYZNewColumn which isn't the ideal solution here.

Thanks,
Dmitrii

Well, it turned out it is quite a small change.
There is a possibility to specify columns explicitly in the Create method but having it defined on the property level is much simpler for end users. There are some situations (like ours) that there are several abstraction layers and it is not quite easy to pass column order to the Create method (because the objects are dynamically created). I created a PR which includes several new unit tests to cover the ordinal scenarios.
Please take a look and let me know if there is something else can be done there.

Thanks,
Dmitrii

Hi, I just started to use FastMember and had the same situation (how to make an order of the properties).

My solution was:

  1. Create an Attribute and create the SortOrder option (in my case to export to Excel).
    public class ExcelAttribute : System.Attribute { public Int32 SortOrder { get; set; } public ExcelAttribute(Int32 sortOrder = 1) { this.SortOrder = sortOrder; } }

  2. In the class use the attribute
    [Excel(SortOrder = 28)] public decimal YTD { get; set; }

  3. Before use FastMember I get the list of properties who have this custom attribute and sort them:
    string[] properties = (from property in typeof(T).GetProperties() where Attribute.IsDefined(property, typeof(ExcelAttribute)) orderby ((ExcelAttribute)property .GetCustomAttributes(typeof(ExcelAttribute), false) .Single()).SortOrder select property.Name).ToArray();
    `

         IEnumerable<#class#> data = lstData;
         DataTable table = new DataTable();
         using (var reader = ObjectReader.Create(data, properties))
         {
             table.Load(reader);
         }`
    

Maybe is not a very efficient code but works for me.

I hope this help.

Regards

This is fixed by #73

Marc, Thank you for your comment and clarification.

My "solution" gets only those properties who have the attribute and sort them, according with the fix # 73 you gets all properties having or not the Ordinal attribute. One more thing I already have ExcelAttribute because I was using PropertyInfo solution.

Is god to know there is an option (Ordinal attribute) when all fields/properties are needed. As I said in my previous post I found your code yesterday. Your code save me a lot of time in my process (is 200% faster than mine)

Again, thank you for your time.

Regards
Gustavo Leal