From 227fa5ed33a51428d8fc500e88b0d5fcbcd24499 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 23 Nov 2024 03:58:08 -0800 Subject: [PATCH] feat(Sort): Sort extension method support IDynamicObject (#4726) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 增加 CastAndOrder 方法 * test: 更新单元测试 * chore: bump version 9.0.2-beta01 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- .../Extensions/LambdaExtensions.cs | 47 ++++++++++++--- .../Extensions/LambadaExtensionsTest.cs | 57 +++++++++++++++++++ 3 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index db2801ace9d..473f55f5005 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 9.0.1 + 9.0.2-beta01 diff --git a/src/BootstrapBlazor/Extensions/LambdaExtensions.cs b/src/BootstrapBlazor/Extensions/LambdaExtensions.cs index 91339bf3bf4..f4932ac86ee 100644 --- a/src/BootstrapBlazor/Extensions/LambdaExtensions.cs +++ b/src/BootstrapBlazor/Extensions/LambdaExtensions.cs @@ -449,12 +449,24 @@ private static IEnumerable EnumerableOrderBy(IEnumerable qu IEnumerable EnumerableOrderBySimple() { + var type = typeof(TItem); IEnumerable? ret = null; - var pi = typeof(TItem).GetPropertyByName(propertyName); - if (pi != null) + if (type.IsInterface && type == typeof(IDynamicObject)) { - var methodName = sortOrder == SortOrder.Desc ? nameof(OrderByDescendingInternal) : nameof(OrderByInternal); - ret = query.AsQueryable().InvokeSortByPropertyInfo(methodName, pi); + var instance = query.FirstOrDefault(); + if (instance != null) + { + ret = CastAndOrder(query, instance.GetType(), propertyName, sortOrder); + } + } + else + { + var pi = type.GetPropertyByName(propertyName); + if (pi != null) + { + var methodName = sortOrder == SortOrder.Desc ? nameof(OrderByDescendingInternal) : nameof(OrderByInternal); + ret = query.AsQueryable().InvokeSortByPropertyInfo(methodName, pi); + } } return ret ?? query; } @@ -476,6 +488,25 @@ IEnumerable EnumerableOrderByComplex() } } + private static IEnumerable? CastAndOrder(IEnumerable query, Type propertyType, string propertyName, SortOrder sortOrder) + { + IEnumerable? ret = null; + var castMethod = typeof(Enumerable).GetMethod(nameof(Enumerable.Cast), BindingFlags.Static | BindingFlags.Public); + if (castMethod != null) + { + var mi = castMethod.MakeGenericMethod(propertyType); + var collection = mi.Invoke(null, [query]); + + var orderMethod = typeof(LambdaExtensions).GetMethod(nameof(EnumerableOrderBy), BindingFlags.Static | BindingFlags.NonPublic); + if (orderMethod != null) + { + var miOrder = orderMethod.MakeGenericMethod(propertyType); + ret = miOrder.Invoke(null, [collection, propertyName, sortOrder]) as IEnumerable; + } + } + return ret; + } + private static IEnumerable EnumerableThenBy(IEnumerable query, string propertyName, SortOrder sortOrder) { return propertyName.Contains('.') ? EnumerableThenByComplex() : EnumerableThenBySimple(); @@ -583,13 +614,13 @@ IQueryable QueryableThenByComplex() private static IOrderedQueryable ThenByDescendingInternalByName(IOrderedQueryable query, string propertyName) => query.ThenByDescending(GetPropertyLambdaByName(propertyName)); - private static IOrderedQueryable OrderByInternal(IQueryable query, System.Reflection.PropertyInfo memberProperty) => query.OrderBy(GetPropertyLambda(memberProperty)); + private static IOrderedQueryable OrderByInternal(IQueryable query, PropertyInfo memberProperty) => query.OrderBy(GetPropertyLambda(memberProperty)); - private static IOrderedQueryable OrderByDescendingInternal(IQueryable query, System.Reflection.PropertyInfo memberProperty) => query.OrderByDescending(GetPropertyLambda(memberProperty)); + private static IOrderedQueryable OrderByDescendingInternal(IQueryable query, PropertyInfo memberProperty) => query.OrderByDescending(GetPropertyLambda(memberProperty)); - private static IOrderedQueryable ThenByInternal(IOrderedQueryable query, System.Reflection.PropertyInfo memberProperty) => query.ThenBy(GetPropertyLambda(memberProperty)); + private static IOrderedQueryable ThenByInternal(IOrderedQueryable query, PropertyInfo memberProperty) => query.ThenBy(GetPropertyLambda(memberProperty)); - private static IOrderedQueryable ThenByDescendingInternal(IOrderedQueryable query, System.Reflection.PropertyInfo memberProperty) => query.ThenByDescending(GetPropertyLambda(memberProperty)); + private static IOrderedQueryable ThenByDescendingInternal(IOrderedQueryable query, PropertyInfo memberProperty) => query.ThenByDescending(GetPropertyLambda(memberProperty)); private static Expression> GetPropertyLambda(PropertyInfo pi) { diff --git a/test/UnitTest/Extensions/LambadaExtensionsTest.cs b/test/UnitTest/Extensions/LambadaExtensionsTest.cs index 76415a824dd..ab24e5c429e 100644 --- a/test/UnitTest/Extensions/LambadaExtensionsTest.cs +++ b/test/UnitTest/Extensions/LambadaExtensionsTest.cs @@ -4,6 +4,7 @@ // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone using System.ComponentModel.DataAnnotations; +using System.Data; using System.Dynamic; using System.Linq.Expressions; @@ -416,6 +417,62 @@ public void Sort_Queryable_Complex() Assert.Equal(10, orderFoos.ElementAt(0).Foo!.Count); } + [Fact] + public void Sort_IDynamicObject_Ok() + { + var dataTable = new DataTable(); + + DataColumn column = new DataColumn + { + DataType = Type.GetType("System.Int32"), + ColumnName = "ID" + }; + dataTable.Columns.Add(column); + + column = new DataColumn + { + DataType = Type.GetType("System.String"), + ColumnName = "Name" + }; + dataTable.Columns.Add(column); + + //Creating some rows + DataRow row = dataTable.NewRow(); + row["ID"] = 1; + row["Name"] = "Bob"; + dataTable.Rows.Add(row); + + row = dataTable.NewRow(); + row["ID"] = 3; + row["Name"] = "Adam"; + dataTable.Rows.Add(row); + + row = dataTable.NewRow(); + row["ID"] = 2; + row["Name"] = "Jane"; + dataTable.Rows.Add(row); + + var context = new DataTableDynamicContext(dataTable, (context, col) => { }); + var items = context.GetItems().ToList(); + + // 未排序 + Assert.Equal("Bob", items[0].GetValue("Name")); + Assert.Equal("Adam", items[1].GetValue("Name")); + Assert.Equal("Jane", items[2].GetValue("Name")); + + // Name 排序 + var nameItems = items.Sort("Name", SortOrder.Asc).ToList(); + Assert.Equal("Adam", nameItems[0].GetValue("Name")); + Assert.Equal("Bob", nameItems[1].GetValue("Name")); + Assert.Equal("Jane", nameItems[2].GetValue("Name")); + + // Name 倒序 + nameItems = items.Sort("Name", SortOrder.Desc).ToList(); + Assert.Equal("Adam", nameItems[2].GetValue("Name")); + Assert.Equal("Bob", nameItems[1].GetValue("Name")); + Assert.Equal("Jane", nameItems[0].GetValue("Name")); + } + [Fact] public void GetPropertyValueLambda_Null() {