C# - code to order by a property using the property name as a string
I would offer this alternative to what everyone else has posted.
System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");
query = query.OrderBy(x => prop.GetValue(x, null));
This avoids repeated calls to the reflection API for obtaining the property. Now the only repeated call is obtaining the value.
However
I would advocate using a PropertyDescriptor
instead, as this will allow for custom TypeDescriptor
s to be assigned to your type, making it possible to have lightweight operations for retrieving properties and values. In the absence of a custom descriptor it will fall back to reflection anyhow.
PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(YourType)).Find("PropertyName");
query = query.OrderBy(x => prop.GetValue(x));
As for speeding it up, check out Marc Gravel's HyperDescriptor
project on CodeProject. I've used this with great success; it's a life saver for high-performance data binding and dynamic property operations on business objects.
Order a list by a property name(string value)?
If you don't have to provide the property name as a string, it's pretty simple using dynamic
:
List<object> l = FillList();
l = l.OrderBy(o => ((dynamic)o).Id);
If the property name has to be a string, then it gets more a bit complicated but can be done using reflection (although it is not very efficient):
l = l.OrderBy(o => o.GetType()
.GetProperty("Code")
.GetValue(o, null));
You should also think about adding some error handling, e.g. if the property doesn't exist.
Also, if all the elements in the list have same runtime type, then it would be much more efficient to compile a getter function using expression trees and reusing it (instead of directly using reflection).
public static Func<object, object> CreateGetter(Type runtimeType, string propertyName)
{
var propertyInfo = runtimeType.GetProperty(propertyName);
// create a parameter (object obj)
var obj = Expression.Parameter(typeof(object), "obj");
// cast obj to runtimeType
var objT = Expression.TypeAs(obj, runtimeType);
// property accessor
var property = Expression.Property(objT, propertyInfo);
var convert = Expression.TypeAs(property, typeof(object));
return (Func<object, object>)Expression.Lambda(convert, obj).Compile();
}
and use it like:
var codeGetter = CreateGetter(l[0].GetType(), "Code"); // using the 1st element as an example
l = l.OrderBy(o => codeGetter(o));
Sorting using property name as string
The solution from your link uses an "Expression.Convert" which most of the time doesn't work with LINQ to Entities.
Here is a working extension method:
public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
{
// LAMBDA: x => x.[PropertyName]
var parameter = Expression.Parameter(typeof(TSource), "x");
Expression property = Expression.Property(parameter, propertyName);
var lambda = Expression.Lambda(property, parameter);
// REFLECTION: source.OrderBy(x => x.Property)
var orderByMethod = typeof(Queryable).GetMethods().First(x => x.Name == "OrderBy" && x.GetParameters().Length == 2);
var orderByGeneric = orderByMethod.MakeGenericMethod(typeof(TSource), property.Type);
var result = orderByGeneric.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<TSource>)result;
}
Disclaimer: I'm the owner of the project EF+ on GitHub.
You can find other methods to order by property name in my repository: GitHub
- OrderByDescending
- ThenBy
- ThenByDescending
- AddOrAppendOrderBy
- AddOrAppendOrderByDescending
EDIT: Answer sub-question
Is it possibly to sort by navigation properties using something like
this, e.g. a property name "NavigationProperty.PropertyName"
Yes, you can either split the string and loop to create the expression with the property path or use a real expression evaluator.
Disclaimer: I'm the owner of the project Eval-Expressions.NET
This library allows you to execute all LINQ method dynamically.
See: LINQ Dynamic
var result = list.OrderByDynamic(x => "NavigationProperty.PropertyName");
How to give Property Name in linq orderBy based on string Property name in C#
The second last of your examples is actually quite close to something that should work.
Ignoring everything around it the following should be a working version of the mentioned example:
// Used reflection
var convertProperty = typeof(Student).GetProperty(columnname);
students.OrderByDescending(n => convertProperty.GetValue(n).ToString() ?? string.Empty).ToListAsync();
To be fair, I haven't tried out this code, so I might have made a mistake somewhere, given this is typed freely without an IDE, but it should give a general Idea, right?
Edit
If you are using C# 6.0 and upwards you can use null checking like mentioned above, otherwise you can also use the following
students.OrderByDescending(n => (convertProperty.GetValue(n) ?? string.Empty).ToString()).ToListAsync();
C# Sort ListT by its property which is string of datetime
Based on your comments on the answers you are looking for a reflection based solution.
The reflection part, to get the value of a property based on the name:
x.GetType().GetProperty(propertyName).GetValue(x, null)
Try this:
var propetyName = "StringAsDate";
var listSorted = list.OrderByDescending(x => DateTime.Parse(Convert.ToString(x.GetType().GetProperty(propertyName).GetValue(x, null))));
If the Property
is already of type DateTime
a cast would be sufficient
var propetyName = "StringAsDate";
var listSorted = list.OrderByDescending(x => (DateTime)x.GetType().GetProperty(propertyName).GetValue(x, null));
Sort List of C# object by STRING parameter
Add reference to nuget package:
https://www.nuget.org/packages/System.Linq.Dynamic/
- Add
using System.Linq.Dynamic;
at the top. - Use
var usersSorted = users.AsQueryable().OrderBy("firstname ASC").ToList();
How to Sort a ListT by a property in the object
The easiest way I can think of is to use Linq:
List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();
Order By String which matches property name gives Null Reference
Order by property name without type reflection
public static class IQueryableExtensions
{
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string
propertyName)
{
return (IQueryable<T>)OrderBy((IQueryable)source, propertyName);
}
public static IQueryable OrderBy(this IQueryable source, string propertyName)
{
var x = Expression.Parameter(source.ElementType, "x");
var body = propertyName.Split('.').Aggregate<string, Expression>(x,
Expression.PropertyOrField);
var selector = Expression.Lambda
(Expression.PropertyOrField(x, propertyName), x);
return source.Provider.CreateQuery(
Expression.Call(typeof(Queryable), "OrderBy", new Type[] {
source.ElementType, selector.Body.Type },
source.Expression, selector
));
}
public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> source,
string propertyName)
{
return (IQueryable<T>)OrderByDescending((IQueryable)source, propertyName);
}
public static IQueryable OrderByDescending(this IQueryable source, string
propertyName)
{
var x = Expression.Parameter(source.ElementType, "x");
var selector = Expression.Lambda(Expression.PropertyOrField(x,
propertyName),x);
return source.Provider.CreateQuery(
Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] {
source.ElementType, selector.Body.Type },
source.Expression, selector
));
}
}
then you can use it like this
var people = DbContext.People
.Select(p => new PersonViewModel{
Name = p.Name,
ManagerId = p.ManagerId,
DepartmentId = p.DepartmentId
})
.OrderBy(paging.Sorting)
or you can do it with type reflection (without IQueryableExtensions) (although it is not very efficient): like this
var people = DbContext.People
.Select(p => new PersonViewModel{
Name = p.Name,
ManagerId = p.ManagerId,
DepartmentId = p.DepartmentId
})
.OrderBy(o => o.GetType()
.GetProperty(paging.Sorting)
.GetValue(o, null))
Ordering by ICollection property using its name as string with Dynamic Linq Library
You can replace the t => t.table2.Select(t2 => t2.field).FirstOrDefault()
with a supported function, Min()
:
OrderBy("table2.Min(field)");
Related Topics
How to Test If Type Is Primitive
How Can a Metro App in Windows 8 Communicate with a Backend Desktop App on the Same MAChine
C# ASP.NET Single Sign-On Implementation
Image Sequence to Video Stream
Windows Service to Run Constantly
How to Create an Immutable Class
To Return Iqueryable<T> or Not Return Iqueryable<T>
How to Redirecttoaction in ASP.NET MVC Without Losing Request Data
Icollection<T> VS List<T> in Entity Framework
In C#, What Happens When You Call an Extension Method on a Null Object
Entity Framework Datetime and Utc
Best Way to Deploy Visual Studio Application That Can Run Without Installing
Implement Validation for Wpf Textboxes
What Are the Benefits to Marking a Field as 'Readonly' in C#
Sometimes Adding a Wcf Service Reference Generates an Empty Reference.Cs
Automatically Inotifypropertychanged
Automapper: Update Property Values Without Creating a New Object