C# 使用Lambda/Linq对对象排序列表
我在字符串中有“按属性排序”的名称。我需要使用Lambda/Linq对对象列表进行排序 例:C# 使用Lambda/Linq对对象排序列表,c#,linq,lambda,linq-to-objects,C#,Linq,Lambda,Linq To Objects,我在字符串中有“按属性排序”的名称。我需要使用Lambda/Linq对对象列表进行排序 例: 公共类员工 { 公共字符串名{set;get;} 公共字符串LastName{set;get;} 公共日期时间DOB{set;get;} } 公共无效排序(参考列表、字符串排序方式、字符串排序方向) { //示例数据: //sortBy=“FirstName” //sortDirection=“ASC”或“DESC” 如果(排序方式==“FirstName”) { list=list.OrderBy(x
公共类员工
{
公共字符串名{set;get;}
公共字符串LastName{set;get;}
公共日期时间DOB{set;get;}
}
公共无效排序(参考列表、字符串排序方式、字符串排序方向)
{
//示例数据:
//sortBy=“FirstName”
//sortDirection=“ASC”或“DESC”
如果(排序方式==“FirstName”)
{
list=list.OrderBy(x=>x.FirstName.toList();
}
}
回答1.: 您应该能够手动构建一个表达式树,该表达式树可以使用名称作为字符串传递到order中。或者你可以按照另一个答案中的建议使用反射,这可能会减少工作量 编辑:下面是一个手动构建表达式树的工作示例。(当只知道属性的名称“Value”时,按X.Value排序)。你可以(应该)建立一个通用的方法来做这件事
using System;
using System.Linq;
using System.Linq.Expressions;
class Program
{
private static readonly Random rand = new Random();
static void Main(string[] args)
{
var randX = from n in Enumerable.Range(0, 100)
select new X { Value = rand.Next(1000) };
ParameterExpression pe = Expression.Parameter(typeof(X), "value");
var expression = Expression.Property(pe, "Value");
var exp = Expression.Lambda<Func<X, int>>(expression, pe).Compile();
foreach (var n in randX.OrderBy(exp))
Console.WriteLine(n.Value);
}
public class X
{
public int Value { get; set; }
}
}
使用系统;
使用System.Linq;
使用System.Linq.Expressions;
班级计划
{
private static readonly rand=new Random();
静态void Main(字符串[]参数)
{
var randX=可枚举范围(0,100)中的n
选择新的X{Value=rand.Next(1000)};
ParameterExpression pe=Expression.Parameter(typeof(X),“value”);
var expression=expression.Property(pe,“值”);
var exp=Expression.Lambda(Expression,pe).Compile();
foreach(randX.OrderBy中的变量n(exp))
控制台写入线(n值);
}
公共X类
{
公共int值{get;set;}
}
}
但是,构建表达式树需要知道参与类型。在您的使用场景中,这可能是问题,也可能不是问题。如果您不知道应该按什么类型排序,那么使用反射可能会更容易
回答2.:
是的,因为如果您没有明确定义比较器,那么Comparer.Default将用于比较。您可以使用反射来获取属性的值
list = list.OrderBy( x => TypeHelper.GetPropertyValue( x, sortBy ) )
.ToList();
public List<Employee> Sort(List<Employee> list, String sortBy, String sortDirection)
{
PropertyInfo property = list.GetType().GetGenericArguments()[0].
GetType().GetProperty(sortBy);
if (sortDirection == "ASC")
{
return list.OrderBy(e => property.GetValue(e, null));
}
if (sortDirection == "DESC")
{
return list.OrderByDescending(e => property.GetValue(e, null));
}
else
{
throw new ArgumentOutOfRangeException();
}
}
其中TypeHelper有一个静态方法,如:
public static class TypeHelper
{
public static object GetPropertyValue( object obj, string name )
{
return obj == null ? null : obj.GetType()
.GetProperty( name )
.GetValue( obj, null );
}
}
您可能还希望从中查看动态LINQ。您可以使用IEnumerable扩展将列表强制转换为IQueryable,然后使用动态链接OrderBy扩展
list = list.AsQueryable().OrderBy( sortBy + " " + sortDirection );
您可以做的一件事是更改
排序
,以便更好地使用lambda
public enum SortDirection { Ascending, Descending }
public void Sort<TKey>(ref List<Employee> list,
Func<Employee, TKey> sorter, SortDirection direction)
{
if (direction == SortDirection.Ascending)
list = list.OrderBy(sorter);
else
list = list.OrderByDescending(sorter);
}
Sort使用IComparable接口(如果类型实现了它)。 您可以通过实现自定义IComparer来避免ifs:
class EmpComp : IComparer<Employee>
{
string fieldName;
public EmpComp(string fieldName)
{
this.fieldName = fieldName;
}
public int Compare(Employee x, Employee y)
{
// compare x.fieldName and y.fieldName
}
}
您可以使用反射来访问该属性
list = list.OrderBy( x => TypeHelper.GetPropertyValue( x, sortBy ) )
.ToList();
public List<Employee> Sort(List<Employee> list, String sortBy, String sortDirection)
{
PropertyInfo property = list.GetType().GetGenericArguments()[0].
GetType().GetProperty(sortBy);
if (sortDirection == "ASC")
{
return list.OrderBy(e => property.GetValue(e, null));
}
if (sortDirection == "DESC")
{
return list.OrderByDescending(e => property.GetValue(e, null));
}
else
{
throw new ArgumentOutOfRangeException();
}
}
公共列表排序(列表、字符串排序、字符串排序方向)
{
PropertyInfo property=list.GetType().GetGenericArguments()[0]。
GetType().GetProperty(sortBy);
如果(排序方向==“ASC”)
{
return list.OrderBy(e=>property.GetValue(e,null));
}
if(sortDirection==“DESC”)
{
return list.OrderByDescending(e=>property.GetValue(e,null));
}
其他的
{
抛出新ArgumentOutOfRangeException();
}
}
注释
通过表达式构建订单可以被读取 不知羞耻地从链接中的页面中窃取:
// First we define the parameter that we are going to use
// in our OrderBy clause. This is the same as "(person =>"
// in the example above.
var param = Expression.Parameter(typeof(Person), "person");
// Now we'll make our lambda function that returns the
// "DateOfBirth" property by it's name.
var mySortExpression = Expression.Lambda<Func<Person, object>>(Expression.Property(param, "DateOfBirth"), param);
// Now I can sort my people list.
Person[] sortedPeople = people.OrderBy(mySortExpression).ToArray();
//首先定义要使用的参数
//在我们的订货条款中。这与“(person=>”相同
//在上面的例子中。
var param=表达式参数(typeof(Person),“Person”);
//现在我们将生成lambda函数,该函数返回
//“DateOfBirth”属性的名称。
var mySortExpression=Expression.Lambda(Expression.Property(param,“DateOfBirth”),param);
//现在我可以对我的人员列表进行排序了。
Person[]sortedPeople=people.OrderBy(mySortExpression.ToArray();
不幸的是,Rashack提供的解决方案不适用于值类型(int、enum等)
对于任何类型的属性,这是我找到的解决方案:
public static Expression<Func<T, object>> GetLambdaExpressionFor<T>(this string sortColumn)
{
var type = typeof(T);
var parameterExpression = Expression.Parameter(type, "x");
var body = Expression.PropertyOrField(parameterExpression, sortColumn);
var convertedBody = Expression.MakeUnary(ExpressionType.Convert, body, typeof(object));
var expression = Expression.Lambda<Func<T, object>>(convertedBody, new[] { parameterExpression });
return expression;
}
公共静态表达式GetLambdaExpressionFor(此字符串sortColumn)
{
var类型=类型(T);
var parameterExpression=Expression.Parameter(类型为“x”);
var body=Expression.PropertyOrField(parameterExpression,sortColumn);
var-convertedBody=Expression.MakeUnary(ExpressionType.Convert,body,typeof(object));
var expression=expression.Lambda(convertedBody,new[]{parameterExpression});
返回表达式;
}
这就是我解决问题的方法:
List<User> list = GetAllUsers(); //Private Method
if (!sortAscending)
{
list = list
.OrderBy(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
else
{
list = list
.OrderByDescending(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
List List=GetAllUsers();//私有方法
如果(!排序)
{
列表=列表
.OrderBy(r=>r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
其他的
{
列表=列表
.OrderByDescending(r=>r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
这可以通过以下方式完成
list.Sort( (emp1,emp2)=>emp1.FirstName.CompareTo(emp2.FirstName) );
NET framework正在将lambda(emp1,emp2)=>int
转换为比较器。
这具有强类型的优点
如果需要降序/逆序,请反转参数
list.Sort( (emp1,emp2)=>emp2.FirstName.CompareTo(emp1.FirstName) );
添加到@Samuel和@bluish所做的操作中。这要短得多,因为在本例中不需要枚举。另外,当升序为所需结果时,您只能传递2个参数,而不是3个,因为true是第三个参数的默认答案
public void Sort<TKey>(ref List<Person> list, Func<Person, TKey> sorter, bool isAscending = true)
{
list = isAscending ? list.OrderBy(sorter) : list.OrderByDescending(sorter);
}
public void Sort(参考列表列表,功能分类器,bool isAscending=true)
{
列表=isA
List<User> list = GetAllUsers(); //Private Method
if (!sortAscending)
{
list = list
.OrderBy(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
else
{
list = list
.OrderByDescending(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
list.Sort( (emp1,emp2)=>emp1.FirstName.CompareTo(emp2.FirstName) );
list.Sort( (emp1,emp2)=>emp2.FirstName.CompareTo(emp1.FirstName) );
public void Sort<TKey>(ref List<Person> list, Func<Person, TKey> sorter, bool isAscending = true)
{
list = isAscending ? list.OrderBy(sorter) : list.OrderByDescending(sorter);
}
private readonly Dictionary<string, Expression<Func<IuInternetUsers, object>>> _sortColumns =
new Dictionary<string, Expression<Func<IuInternetUsers, object>>>()
{
{ nameof(ContactSearchItem.Id), c => c.Id },
{ nameof(ContactSearchItem.FirstName), c => c.FirstName },
{ nameof(ContactSearchItem.LastName), c => c.LastName },
{ nameof(ContactSearchItem.Organization), c => c.Company.Company },
{ nameof(ContactSearchItem.CustomerCode), c => c.Company.Code },
{ nameof(ContactSearchItem.Country), c => c.CountryNavigation.Code },
{ nameof(ContactSearchItem.City), c => c.City },
{ nameof(ContactSearchItem.ModifiedDate), c => c.ModifiedDate },
};
private IQueryable<IuInternetUsers> SetUpSort(IQueryable<IuInternetUsers> contacts, string sort, string sortDir)
{
if (string.IsNullOrEmpty(sort))
{
sort = nameof(ContactSearchItem.Id);
}
_sortColumns.TryGetValue(sort, out var sortColumn);
if (sortColumn == null)
{
sortColumn = c => c.Id;
}
if (string.IsNullOrEmpty(sortDir) || sortDir == SortDirections.AscendingSort)
{
contacts = contacts.OrderBy(sortColumn);
}
else
{
contacts = contacts.OrderByDescending(sortColumn);
}
return contacts;
}