C# 如何动态存储用于Linq Orderby的表达式?
我正在尝试创建一个快速类,这样我就可以更容易地使用和维护网格的排序代码,并减少代码重复。为此,我设计了以下课程:C# 如何动态存储用于Linq Orderby的表达式?,c#,linq,expression,C#,Linq,Expression,我正在尝试创建一个快速类,这样我就可以更容易地使用和维护网格的排序代码,并减少代码重复。为此,我设计了以下课程: public class SortConfig<TSource, TRelatedObject> where TSource : class where TRelatedObject : class { public IList<SortOption> Options { get; protected set; } public SortOpt
public class SortConfig<TSource, TRelatedObject> where TSource : class where TRelatedObject : class
{
public IList<SortOption> Options { get; protected set; }
public SortOption DefaultOption { get; set; }
public SortConfig()
{
Options = new List<SortOption>();
}
public void Add(string name, Expression<Func<TSource, object>> sortExpression, TRelatedObject relatedObject, bool isDefault = false)
{
var option = new SortOption
{
FriendlyName = name,
SortExpression = sortExpression,
RelatedObject = relatedObject
};
Options.Add(option);
if (isDefault)
DefaultOption = option;
}
public SortOption GetSortOption(string sortName)
{
if (sortName.EndsWith("asc", StringComparison.OrdinalIgnoreCase))
sortName = sortName.Substring(0, sortName.LastIndexOf("asc", StringComparison.OrdinalIgnoreCase));
else if (sortName.EndsWith("desc", StringComparison.OrdinalIgnoreCase))
sortName = sortName.Substring(0, sortName.LastIndexOf("desc", StringComparison.OrdinalIgnoreCase));
sortName = sortName.Trim();
var option = Options.Where(x => x.FriendlyName.Trim().Equals(sortName, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
if (option == null)
{
if (DefaultOption == null)
throw new InvalidOperationException(
string.Format("No configuration found for sort type of '{0}', and no default sort configuration exists", sortName));
option = DefaultOption;
}
return option;
}
public class SortOption
{
public string FriendlyName { get; set; }
public Expression<Func<TSource, object>> SortExpression { get; set; }
public TRelatedObject RelatedObject { get; set; }
}
}
当排序的变量是字符串时,这非常有效,但当它不是字符串时,我得到以下异常:无法按类型“System.Object”排序。
我假设这是因为我将表达式存储为expression
,而不是更具体地描述第二个泛型。我不明白如何在一个类中保留所有不同的排序选项(即使是非字符串属性)
我想其中的一个问题是Linq.OrderBy()
子句将表达式作为参数,但我并不想知道Linq.OrderBy()
如何推断TKey
应该是什么,因此,我无法理解如何利用这一推断,用适当的TKey
存储这些表达式
有什么想法吗?一般的论点是这样推断的:
IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> enumerable, Func<TSource, TKey> expression)
由于我们从一个IEnumerable
开始,编译器可以推断它期望的表达式是Func
,因为扩展正在影响IEnumerable
。接下来,由于表达式返回一个值,编译器可以推断出剩余的类型,在这种情况下,int
,因此在本例中它变成了Func
现在,与您的特定问题密切相关的是,如果您适当地泛化SortConfig
对象,您可以轻松地设置表达式以使其正常工作。看起来您的SortConfig
现在接受了Func
委托。如果将SortConfig
泛化为使用另一种类型,则会获得特定性。例如:
void Add<TSource, TKey>(string name, Func<TSource, TKey> expression)
看一看Thank,但我宁愿指定代码而不是指定字符串,特别是因为我的网格的数据结构与我的数据库不是1:1数据模型,因此,排序需要从指定的网格转换为db排序。无论如何,当您获得排序选项时,您不是在使用魔术字符串吗?我现在使用的魔术字符串只是客户端魔术字符串。客户端的表达式意味着如果我的DB列更改了名称,排序就会中断。如果网格的排序字符串发生变化,那么比系统范围的db名称发生变化时,本地化的变化要大得多。我觉得奇怪的是,它会与字符串一起工作。这意味着它可能正确地使用了字符串的IComparable接口。如果您确保每个存储的变量类型都实现了IComparable,那么可能会这样做?不是答案,但可能会有帮助。我有点明白你的意思,但是void
Add
方法到底是怎么回事?你是说\u sortConfig.Add
?是的,我实际上不知道你的方法签名是什么,所以我不得不假设它。这是有道理的,除了我“我不确定给SortOption.SortExpression
属性什么类型来存储我的表达式让我模拟一个简单的例子来说明代码。举例来说,它可能有点复杂。啊,我甚至没有想到用界面隐藏TKey
。非常感谢:)
IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> enumerable, Func<TSource, TKey> expression)
Enumerable.Range(0, 10).OrderBy(x => x)
void Add<TSource, TKey>(string name, Func<TSource, TKey> expression)
public class SortConfig<TSource>
static void Main(string[] args)
{
var list = Enumerable.Range(0, 10).Reverse().Select(x => new SampleClass { IntProperty = x, StringProperty = x + "String", DateTimeProperty = DateTime.Now.AddDays(x * -1) });
SortContainer<SampleClass> container = new SortContainer<SampleClass>();
container.Add("Int", x => x.IntProperty);
container.Add("String", x => x.StringProperty);
container.Add("DateTime", x => x.DateTimeProperty);
var sorter = container.GetSorterFor("Int");
sorter.Sort(list).ForEach(x => Console.WriteLine(x.IntProperty));
Console.ReadKey();
}
public class SampleClass
{
public int IntProperty { get; set; }
public string StringProperty { get; set; }
public DateTime DateTimeProperty { get; set; }
}
public class SortContainer<TSource>
{
protected Dictionary<string, ISorter<TSource>> _sortTypes = new Dictionary<string, ISorter<TSource>>();
public void Add<TKey>(string name, Func<TSource, TKey> sortExpression)
{
Sorter<TSource, TKey> sorter = new Sorter<TSource, TKey>(sortExpression);
_sortTypes.Add(name, sorter);
}
public ISorter<TSource> GetSorterFor(string name)
{
return _sortTypes[name];
}
}
public class Sorter<TSource, TKey> : ISorter<TSource>
{
protected Func<TSource, TKey> _sortExpression = null;
public Sorter(Func<TSource, TKey> sortExpression)
{
_sortExpression = sortExpression;
}
public IOrderedEnumerable<TSource> Sort(IEnumerable<TSource> sourceEnumerable)
{
return sourceEnumerable.OrderBy(_sortExpression);
}
}
public interface ISorter<TSource>
{
IOrderedEnumerable<TSource> Sort(IEnumerable<TSource> sourceEnumerable);
}