无法使用Int64强制转换System.Func`2类型的对象

Müs*_*ÜRK 5 c# linq reflection dynamic

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using dynamic = System.Linq.Dynamic;
using System.Linq.Expressions;

namespace Project.Lib.Extensions
{
    public static partial class Utils
    {
        public static List<T> SortForMe<T>(this List<T> list, string propertyName,SortDirection sortDirection)
        {
            string exp1 = string.Format("model.{0}", propertyName);
            var p1 = Expression.Parameter(typeof(T), "model");
            var e1 = dynamic.DynamicExpression.ParseLambda(new[] { p1 }, null, exp1);

            if (e1 != null)
            {
                if (sortDirection==SortDirection.Ascending)
                {
                    var result = list.OrderBy((Func<T, object>)e1.Compile()).ToList();
                    return result;
                }
                else
                {
                    var result = list.OrderByDescending((Func<T, object>)e1.Compile()).ToList();
                    return result;
                }
            }
            return list;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用此代码按propertyName对我的通用列表进行排序.当属性类型为string,此代码成功运行,但当类型为long或时int,我收到此异常:

无法将类型为'System.Func`2 [Project.Lib.Model.UserQueryCount,System.Int64]'的对象强制转换为'System.Func`2 [Project.Lib.Model.UserQueryCount,System.Object]'.


var result = list.OrderBy((Func<T, dyamic>)e1.Compile()).ToList();
Run Code Online (Sandbox Code Playgroud)

在上面的行中,我决定使用dynamic,但再次获得例外.我该怎么办?


我改变了我的方法:

public static List<TModel> SortForMe<TModel>(this List<TModel> list, string propertyName,SortDirection sortDirection) where TModel:class
    {
        var ins = Activator.CreateInstance<TModel>();
        var prop= ins.GetType().GetProperty(propertyName);
        var propertyType =  prop.PropertyType;

    string exp1 = string.Format("model.{0}", propertyName);
    var p1 = System.Linq.Expressions.Expression.Parameter(typeof(TModel), "model");
    var e1 = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p1 }, null, exp1);

    if (e1 != null)
    {
        if (sortDirection==SortDirection.Ascending)
        {
            return list.OrderBy((Func<TModel, propertyType>)e1.Compile()).ToList();
        }

        return list.OrderByDescending((Func<TModel, propertyType>)e1.Compile()).ToList();
    }
        return list;
}
Run Code Online (Sandbox Code Playgroud)

我使用反射获得了propertyType但在Func中我不能像这样使用它:"Func<TModel, propertyType>"有没有办法解决这个问题

谢谢您的帮助.

Nik*_*sev 0

我怀疑这与值类型的装箱有关,但我不能确定。但是,有一种不涉及拳击的解决方法,既可以解决您的问题,又可以使您的方法更易于使用。

您实际上可以使用返回属性的 lambda 表达式,而不是标识要排序的属性的字符串。这可以通过以下方法完成:

private static string GetPropertyName<TObject, TProperty>(Expression<Func<TObject,     TProperty>> property)
{
    MemberExpression memberExpression = (MemberExpression)property.Body;
    PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;

    return propertyInfo.Name;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我已将Func委托包装到Expression类型中(您可能想阅读更多相关信息)。这样,我可以询问该表达式并找出它使用了哪些成员。当然,除了简单的x => x.Propertylambda 之外,这对于所有其他表达式都会失败,因此您可能需要进行一些错误检查。

要使用它,您必须稍微更改您的扩展方法:

public static List<TObject> SortForMe<TObject, TProperty>(
    this List<TObject> list, 
    Expression<Func<TObject, TProperty>> property, 
    SortDirection sortDirection)
{
     string propertyName = GetPropertyName(property);
     ...
     ...          
     // when casting compiled expression to Func, instead of object, use TProperty
     // that way, you will avoid boxing
     var result = list.OrderBy((Func<T, TProperty>)e1.Compile()).ToList();
     ...
     ...
}
Run Code Online (Sandbox Code Playgroud)

实际用法可能如下所示:

List<Foo> foos = ... ;
foos.SortForMe(x => x.IntegerProperty, SortDirection.Ascending);
foos.SortForMe(x => x.StringProperty, SortDirection.Ascending);
Run Code Online (Sandbox Code Playgroud)

和是在类型上定义IntegerPropertyStringProperty实际属性Foo。使用该方法时无需指定实际的类型参数 - C# 的类型推断在这里非常好地发挥作用。