Reputation: 93
I have a custom attribute that I apply to properties on a class. This attribute is used for exporting the class's properties to a flat file.
One of the attribute's properties is FieldOrder
. I need to make sure the order in which I export the properties of the class is correct. Also, not all properties on the class will have the custom attribute.
I found this article: How do I sort a generic list based on a custom attribute? This solution assumes all properties have the custom attribute, which isn't my case. I was also hoping for more elegant solution.
Your help is greatly appreciated!
public interface IFileExport{}
public class ExportAttribute: Attribute
{
public int FieldOrder { get; set; }
public int FieldLength { get; set; }
public ExportAttribute() { }
}
public class ExportClass: IFileExport
{
[ExportAttribute( FieldOrder = 2, FieldLength = 25 )]
public string LastName { get; set; }
[ExportAttribute( FieldOrder=1, FieldLength=25)]
public string FirstName { get; set; }
[ExportAttribute( FieldOrder = 3, FieldLength = 3 )]
public int Age { get; set; }
public ExportClass() { }
}
public class TestClass
{
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder
(IFileExport fileExport)
{
//get all properties on the IFileExport object
PropertyInfo[] allProperties = fileExport
.GetType()
.GetProperties( BindingFlags.Instance | BindingFlags.Public );
// now I need to figure out which properties have the ExportAttribute
//and sort them by the ExportAttribute.FieldOrder
}
}
UPDATE: I'm ordering the properties by ExportAttribute.FieldOrder Ascending
Upvotes: 9
Views: 15200
Reputation: 126
You can use either of the following options.
First option: pass anonymous function to OrderBy
return allProperties.OrderBy(m => m.GetCustomAttribute<ExportAttribute>() == null ? -1 :
m.GetCustomAttribute<ExportAttribute>().FieldOrder).ToList();
Second option: create the function for selecting the key and pass it to OrderBy
return allProperties.OrderBy(KeySelector).ToList();
The key selector function is defined as in here:
public static int KeySelector(PropertyInfo info)
{
ExportAttribute attr = info.GetCustomAttribute<ExportAttribute>();
return attr == null ? -1 : attr.FieldOrder;
}
If the property does not have ExportAttribute, the selector will return -1. You can choose any other default value.
The second approach lets you define other types of selectors for ordering and just call the new selector you have defined.
Upvotes: 1
Reputation: 7921
static void Main(string[] args)
{
//get all properties on the IFileExport object
PropertyInfo[] allProperties = fileExport.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
Array.Sort(allProperties, ArrayAttributeComparison);
}
private static int ArrayAttributeComparison(PropertyInfo x, PropertyInfo y)
{
//Do null checks here
ExportAttribute xExportAttribute = GetExportAtribute(x);
ExportAttribute yExportAttribute = GetExportAtribute(x);
//Do null checks here
return xExportAttribute.FieldOrder - yExportAttribute.FieldOrder;
}
private static ExportAttribute GetExportAtribute(PropertyInfo propertyInfo)
{
object[] attributes = propertyInfo.GetCustomAttributes(true);
foreach (var t in attributes)
{
if (t is ExportAttribute)
{
return (ExportAttribute)t;
}
}
return null;
}
Upvotes: 0
Reputation: 77536
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder( IFileExport fileExport )
{
PropertyInfo[] allProperties = GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(x => new
{
Property = x,
Attribute = (ExportAttribute)Attribute.GetCustomAttribute(x, typeof(ExportAttribute), true)
})
.OrderBy(x => x.Attribute != null ? x.Attribute.FieldOrder : -1)
.Select(x => x.Property)
.ToArray();
}
Since you didn't explain how you wanted properties without the attribute ordered, I have made it so that they would be at the beginning. But the gist of this code is:
FieldOrder
, using -1
for properties without the attribute. (not sure what you wanted here)PropertyInfo
PropertyInfo[]
array. Upvotes: 29
Reputation: 1953
You should be able to use the GetCustomAttributes() method on each PropertyInfo to filter the properties with the correct attributes, and then sort the remaining items.
Upvotes: 0