gpt4 book ai didi

c# - 如何动态存储用于 Linq Orderby 的表达式?

转载 作者:太空狗 更新时间:2023-10-29 23:16:54 25 4
gpt4 key购买 nike

我正在尝试创建一个快速类,以便我可以更轻松地使用和维护为网格编写排序代码,并减少代码重复。为此,我提出了以下类(class):

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; }
}
}

这个想法是您创建不同排序选项的快速配置,为此使用的 OrderBy 表达式,以及可选的与该排序选项相关的对象。这使我的代码看起来像:

    protected void InitSortConfig()
{
_sortConfig = new SortConfig<xosPodOptimizedSearch, HtmlAnchor>();
_sortConfig.Add("name", (x => x.LastName), lnkSortName, true);
_sortConfig.Add("team", (x => x.SchoolName), lnkSortTeam);
_sortConfig.Add("rate", (x => x.XosRating), lnkSortRate);
_sortConfig.Add("pos", (x => x.ProjectedPositions), null);
_sortConfig.Add("height", (x => x.Height), lnkSortHeight);
_sortConfig.Add("weight", (x => x.Weight), lnkSortWeight);
_sortConfig.Add("city", (x => x.SchoolCity), lnkSortCity);
_sortConfig.Add("state", (x => x.SchoolState), lnkSortState);
}

然后我就可以排序了

        // Get desired sorting configuration
InitSortConfig();
var sortOption = _sortConfig.GetSortOption(sort);
bool isDescendingSort = sort.EndsWith("desc", StringComparison.OrdinalIgnoreCase);

// Setup columns
InitSortLinks();
if (sortOption.RelatedObject != null)
{
// Make modifications to html anchor
}

// Form query
var query = PodDataContext.xosPodOptimizedSearches.AsQueryable();

if (isDescendingSort)
query = query.OrderByDescending(sortOption.SortExpression);
else
query = query.OrderBy(sortOption.SortExpression);

当排序的变量是字符串时,这很有效,但当它不是字符串时,我得到以下异常:Cannot order by type 'System.Object'.

我假设这是因为我将表达式存储为 Expression<Func<TSource, object>>并没有更具体地说明第二个通用的。我不明白如何将所有不同的排序选项(即使是非字符串属性)保留在一个类中。

我想问题之一是 Linq.OrderBy()子句采用 Expression<Func<TSource, TKey>>因为它是参数,但我并没有思考如何 Linq.OrderBy()能够推断出什么 TKey应该是,因此我无法理解如何利用该推理以适当的方式存储这些表达式 TKey .

有什么想法吗?

最佳答案

通用参数是这样推断的:

IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> enumerable, Func<TSource, TKey> expression)

当你有一个 IEnumerable<T> ,编译器能够推断出 TSourceT在这种情况下,因为扩展方法声明;所以扩展方法已经在知道什么的情况下添加了TSource是。例如:

Enumerable.Range(0, 10).OrderBy(x => x)

因为我们从 IEnumerable<int> 开始, 编译器可以推断出它期望的表达式是 Func<int, TKey> ,因为扩展正在影响 IEnumerable<int> .接下来,因为你的表达式返回一个值,编译器可以推断出剩余的类型,在这种情况下 int , 所以它变成了 Func<int, int>用这个例子。

现在,与您的特定问题密切相关,如果您将 SortConfig 泛化,您可以轻松地设置表达式以适本地工作。适当反对。它看起来像你的 SortConfig需要 Func<TSource, object>现在委托(delegate)。如果您通用化您的 SortConfig要使用另一种类型,您会获得特异性。示例:

 void Add<TSource, TKey>(string name, Func<TSource, TKey> expression)

这里的下一个问题是如何以某种格式存储支持方法。你的类声明看起来像这样:

 public class SortConfig<TSource>

那么当您调用 OrderBy 时,所有数据类型都应该对齐扩展名。

编辑:这是我认为您想做的工作示例:

    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);
}

关于c# - 如何动态存储用于 Linq Orderby 的表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10487248/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com