gpt4 book ai didi

c# - 从字符串构建 Linq 排序表达式结果为 'Expression of "system.int3 2"can not be used for return type "System.Object"'

转载 作者:行者123 更新时间:2023-12-05 04:28:24 28 4
gpt4 key购买 nike

我有一个系统应该根据另一个应用程序提供的排序数据列表创建排序表达式。排序信息作为包含排序键 (Object.thingtosort) 和方向的对象给出。

我当前的解决方案是围绕我从另一个堆栈溢出问题得到的解决方案构建的,可在此处找到:original question .每当我运行以下代码时:

    static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);
var func = Expression.Lambda<Func<T, object>>(body, parameter); //<-- line of error
return func;
}

我得到错误:

System.ArgumentException: 'Expression of type 'System.Int32' cannot be used for return type 'System.Object''

我尝试通过使用将参数转换为对象来解决此问题

    Expression.Convert(body, typeof(object));

导致以下功能:

static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);
var convertedBody = Expression.Convert(body, typeof(object));
var func = Expression.Lambda<Func<T, object>>(convertedBody, parameter); //<-- line of error
return func;
}

这会产生另一个问题,它无法比较数组中的两个元素(可能是因为在这种情况下它不知道如何比较对象)。

System.InvalidOperationException: 'Failed to compare two elements in the array.'
ArgumentException: At least one object must implement IComparable.

我希望它适用于任何类型,因为排序应该适用于我的对象的任何字段(这些可以嵌套多层)。下面包含了重现我的问题所需的完整代码。

Microsoft Visual Studio Community 2022(64 位)- 预览版版本 17.3.0 预览 1.1

该项目是一个使用 .net 6 的控制台应用程序。


using System.Linq.Expressions;

internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("Hello, World!");

string propertyForExpression = "Product.randomNumber";

Random random = new Random();

List<OrderEntity> orders = new List<OrderEntity>();

for (int i = 1; i < 11; i++)
{
var orderToAdd = new OrderEntity();
orderToAdd.id = i;
orderToAdd.name = "order number " + i;

var productToAdd = new ProductEntity();
productToAdd.id = i;
productToAdd.productName = "product " + i;
productToAdd.description = "this is a product";
productToAdd.randomNumber = random.Next(1, 100);

orderToAdd.Product = productToAdd;
orders.Add(orderToAdd);
}

var sortedOrders = orders.OrderBy(X => ToLambda<OrderEntity> (propertyForExpression));

foreach(var order in sortedOrders)
{
Console.WriteLine(order.Product.randomNumber);
}
Console.ReadKey();
}

static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);
var func = Expression.Lambda<Func<T, object>>(body, parameter);
return func;
}


// ToLambda function that crashes on the OrderBy with error: System.InvalidOperationException: 'Failed to compare two elements in the array.'

//static Expression<Func<T, object>> ToLambda<T>(string propertyName)
//{
// var propertyNames = propertyName.Split('.');
// var parameter = Expression.Parameter(typeof(T));
// Expression body = parameter;
// foreach (var propName in propertyNames)
// body = Expression.Property(body, propName);
// var convertedBody = Expression.Convert(body, typeof(object));
// var func = Expression.Lambda<Func<T, object>>(convertedBody, parameter);
// return func;
//}
}


public class OrderEntity
{
public int id { get; set; }
public string name { get; set; }
public ProductEntity Product { get; set; }
}

public class ProductEntity
{
public int id { get; set; }
public string productName { get; set; }
public string description { get; set; }
public int randomNumber { get; set; }
}

最佳答案

这似乎最终是一个小错误。

  1. 您正在尝试通过 Expression<Func<T, object>> 订购(与那个值一样,不是 randomNumber 的值决定排序顺序。
  2. .OrderBy对于枚举(不可查询)期望一个 Func<TSource, TKey>其中 TSourceOrderEntityTKey应该是你的 object在这种情况下的值(value)。

所以我们需要做两件事:

  1. 编译表达式。
  2. 用它来排序。

本质上我们需要这个

Func<OrderEntity, object> sortAccessor = ToLambda<OrderEntity>(propertyForExpression).Compile();
var sortedOrders = orders.OrderBy(sortAccessor);

Func<OrderEntity, object> sortAccessor = ToLambda<OrderEntity>(propertyForExpression).Compile();
var sortedOrders = orders.OrderBy(x => sortAccessor(x));

var sortedOrders = orders.OrderBy(x => ToLambda<OrderEntity>(propertyForExpression).Compile()(x));

var sortedOrders = orders.OrderBy(ToLambda<OrderEntity>(propertyForExpression).Compile());

您还可以更改方法以返回已编译的 Func<T, object>相反:

static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);

var convertedResult = Expression.Convert(body, typeof(object));

var func = Expression.Lambda<Func<T, object>>(convertedResult, parameter);
return func;
}

然后像这样使用它:

Func<OrderEntity, object> sortAccessor = ToLambda<OrderEntity>(propertyForExpression);
var sortedOrders = orders.OrderBy(sortAccessor);

或者这个:

var sortedOrders = orders.OrderBy(ToLambda<OrderEntity>(propertyForExpression));

注意:我建议在循环外编译表达式并将其缓存为 Func<OrderEntity, object> 的原因变量是因为否则它将针对单个 .OrderBy 进行多次评估.

关于c# - 从字符串构建 Linq 排序表达式结果为 'Expression of "system.int3 2"can not be used for return type "System.Object"',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72614282/

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