C# 动态排序列表<;T>;财产
我知道已经有人问过一些类似的问题,但大多数答案都依赖于Linq,我对在这里使用Linq不感兴趣(出于性能原因) 我很想知道是否有人有任何解决方案可以使用运行时确定的值对列表进行动态排序。到目前为止,我只能用if-else的/switch找到一些东西 下面是我用来搞乱并尝试使其工作的示例代码。它是一个控制台应用程序,由一个小模型类、一个分类器类(实现IComparer)和Main()方法组成: 项目模型类C# 动态排序列表<;T>;财产,c#,.net,C#,.net,我知道已经有人问过一些类似的问题,但大多数答案都依赖于Linq,我对在这里使用Linq不感兴趣(出于性能原因) 我很想知道是否有人有任何解决方案可以使用运行时确定的值对列表进行动态排序。到目前为止,我只能用if-else的/switch找到一些东西 下面是我用来搞乱并尝试使其工作的示例代码。它是一个控制台应用程序,由一个小模型类、一个分类器类(实现IComparer)和Main()方法组成: 项目模型类 public class Project { public int ProjID {
public class Project
{
public int ProjID { get; set; }
public string Title { get; set; }
public string Owner { get; set; }
public DateTime Created { get; set; }
public override string ToString()
{
return string.Format("-- ProjID: {0}, Title: {1}, Owner: {2}, Created on {3}", ProjID, Title, Owner, Created);
}
}
比较器方法
public class ProjectSorter : IComparer<Project>
{
public string Prop { get; set; }
// ctor, what do you want to sort by?
public ProjectSorter(string prop)
{
Prop = prop;
}
public ProjectSorter() { }
int IComparer<Project>.Compare(Project x, Project y)
{
if (this.Prop == "ProjID") {
return x.ProjID.CompareTo(y.ProjID);
}
else if (Prop == "Title")
{
return x.Title.CompareTo(y.Title);
}
else if (Prop == "Created")
{
return x.Created.CompareTo(y.Created);
}
// etc...
return 0; // just to get this method working
}
}
公共类项目排序器:IComparer
{
公共字符串属性{get;set;}
//ctor,你想按什么排序?
公共项目分拣机(字符串道具)
{
道具=道具;
}
公共项目排序器(){}
int IComparer.Compare(项目x、项目y)
{
if(this.Prop==“ProjID”){
返回x.ProjID.CompareTo(y.ProjID);
}
否则如果(道具=“标题”)
{
返回x.Title.CompareTo(y.Title);
}
否则如果(道具==“已创建”)
{
返回x.Created.CompareTo(y.Created);
}
//等等。。。
返回0;//只是为了使此方法正常工作
}
}
主要方法(测试比较器/分拣机)
static void Main(字符串[]args)
{
列表项目列表=新列表
{
新项目{ProjID=1,Title=“First Proj”,Owner=“rushfive”,Created=DateTime.Now},
新项目{ProjID=2,Title=“2nd Proj”,Owner=“rushfive”,Created=DateTime.Now.AddDays(-2)},
新项目{ProjID=3,Title=“惊人的重做”,Owner=“waldrw”,Created=DateTime.Now},
新项目{ProjID=4,Title=“Eat午餐”,Owner=“jedlow”,Created=DateTime.Now.AddDays(-5)},
新项目{ProjID=5,Title=“更新实验室”,Owner=“somsky”,Created=DateTime.Now},
};
Console.WriteLine(“\n以默认顺序列出项目:”);
foreach(项目列表中的项目p)
{
控制台写入线(p);
}
Console.WriteLine(“\n现在,列出按标题排序的项目:”);
IComparer comparer1=新项目排序器(“标题”);
projectList.Sort(comparer1);
foreach(项目列表中的项目p)
{
控制台写入线(p);
}
Console.WriteLine(“\n现在,列出按创建日期排序的项目:”);
IComparer comparer2=新项目排序器(“已创建”);
projectList.Sort(comparer2);
foreach(项目列表中的项目p)
{
控制台写入线(p);
}
}
鉴于我上面的当前实现,它可以根据属性对列表进行正确的动态排序。。但是通过使用可能很长的if-else/switch逻辑
有没有更好的方法来实现这种排序?对于我来说,一个常见的用例是,用户将单击浏览器中的某个内容,以获得按特定属性排序的列表
似乎使用一个巨大的if-else/开关可能是不必要的,但我不知道还有其他方法(考虑更优雅、更少的代码)。与其他一些语言相比,javascript的表现力有多强,也许我有点被宠坏了
关于这个问题有什么想法吗?我会制作一个包装器,它接受一个lambda来执行从
项目
到比较对象的转换
注意,这假设所有涉及的类型都实现了IComparable
您可以使用这样的通用比较器:
/// <summary>
/// Generic comparer by key selector
/// </summary>
public class KeySelectorComparer<T, TProperty> : Comparer<T> where TProperty : IComparable<TProperty>
{
private readonly Func<T, TProperty> keySelector;
public KeySelectorComparer(Func<T, TProperty> keySelector)
{
if (keySelector == null)
throw new ArgumentException("'keySelector' parameter can not be null.", "keySelector");
this.keySelector = keySelector;
}
public bool Equals(T x, T y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
return false;
return this.keySelector(x).Equals(this.keySelector(y));
}
public int GetHashCode(T obj)
{
if (ReferenceEquals(obj, null)) return 0;
return this.keySelector(obj).GetHashCode();
}
public override int Compare(T x, T y)
{
if (x == null)
{
if (y == null)
return 0;
return 1;
}
if (y == null)
return -1;
return this.keySelector(x).CompareTo(this.keySelector(y));
}
}
//
///键选择器通用比较器
///
public类KeySelectorComparer:Comparer,其中TProperty:IComparable
{
专用只读Func键选择器;
公用密钥选择器比较程序(Func密钥选择器)
{
if(keySelector==null)
抛出新ArgumentException(“'keySelector'参数不能为null。”,“keySelector”);
this.keySelector=keySelector;
}
公共布尔等于(TX,TY)
{
if(ReferenceEquals(x,y))返回true;
if(ReferenceEquals(x,null)| | ReferenceEquals(y,null))
返回false;
返回this.keySelector(x).Equals(this.keySelector(y));
}
公共int GetHashCode(T obj)
{
if(ReferenceEquals(obj,null))返回0;
返回此.keySelector(obj).GetHashCode();
}
公共覆盖整型比较(TX,TY)
{
如果(x==null)
{
如果(y==null)
返回0;
返回1;
}
如果(y==null)
返回-1;
返回此.keySelector(x).CompareTo(此.keySelector(y));
}
}
因此,您可以根据所需的键选择器来比较所需的任何集合,如下所示:
var list = new List<MyObj>();
list.Sort(new KeySelectorComparer<MyObj, int>(s=> s.Id));
var list=newlist();
排序(newkeyselectorcomparer(s=>s.Id));
首先,由于性能原因,没有对Linq进行排序,我不认为这会有什么不同。请说明Linq在您的应用程序中造成性能下降、内存压力或类似问题的地方,我会非常惊讶。
所以,假设我们需要一种通用的排序方法,其中我们提供一个属性名。如果我们可以提供一个表达式,它将更容易:
class PropertyComparer<T> : IComparer<T>
{
private readonly Func<T, IComparable> _selector;
public PropertyComparer(Func<T, IComparable> selector)
{
this._selector = selector;
}
public int Compare(T x, T y)
{
var left = this._selector(x);
var right = this._selector(y);
if (left == null)
{
if (right == null)
return 0;
else
return -right.CompareTo(null);
}
else
{
return left.CompareTo(right);
}
}
}
类属性比较者:IComparer
{
专用只读函数选择器;
公共属性比较程序(功能选择器)
{
这个._选择器=选择器;
}
公共整数比较(TX,TY)
{
var left=该选择器(x);
var right=该选择器(y);
if(left==null)
{
if(right==null)
返回0;
其他的
return-右。CompareTo(null);
}
其他的
{
返回左侧。比较(右侧);
}
}
}
否则,我们必须建立一个:
class PropertyComparer<T> : IComparer<T>
{
private readonly Func<T, IComparable> _selector;
public PropertyComparer(string propertyName)
{
var selectorParameter = Expression.Parameter(typeof (T), "x"); //parameter [T x]
var property = Expression.PropertyOrField(selectorParameter, propertyName); // [x.Property]
var cast = Expression.Convert(property, typeof(IComparable)); // [x.Property as IComparable]
this._selector = Expression.Lambda<Func<T, IComparable>>(cast, selectorParameter).Compile();
}
public int Compare(T x, T y)
{
var left = this._selector(x);
var right = this._selector(y);
if (left == null)
{
if (right == null)
return 0;
else
return -right.CompareTo(null);
}
else
{
return left.CompareTo(right);
}
}
}
类属性比较者:IComparer
{
专用只读函数选择器;
公共财产公司
var list = new List<MyObj>();
list.Sort(new KeySelectorComparer<MyObj, int>(s=> s.Id));
class PropertyComparer<T> : IComparer<T>
{
private readonly Func<T, IComparable> _selector;
public PropertyComparer(Func<T, IComparable> selector)
{
this._selector = selector;
}
public int Compare(T x, T y)
{
var left = this._selector(x);
var right = this._selector(y);
if (left == null)
{
if (right == null)
return 0;
else
return -right.CompareTo(null);
}
else
{
return left.CompareTo(right);
}
}
}
class PropertyComparer<T> : IComparer<T>
{
private readonly Func<T, IComparable> _selector;
public PropertyComparer(string propertyName)
{
var selectorParameter = Expression.Parameter(typeof (T), "x"); //parameter [T x]
var property = Expression.PropertyOrField(selectorParameter, propertyName); // [x.Property]
var cast = Expression.Convert(property, typeof(IComparable)); // [x.Property as IComparable]
this._selector = Expression.Lambda<Func<T, IComparable>>(cast, selectorParameter).Compile();
}
public int Compare(T x, T y)
{
var left = this._selector(x);
var right = this._selector(y);
if (left == null)
{
if (right == null)
return 0;
else
return -right.CompareTo(null);
}
else
{
return left.CompareTo(right);
}
}
}