【问题标题】:Unable to cast object of type System.Func`2 with Int64无法使用 Int64 转换 System.Func`2 类型的对象
【发布时间】:2012-08-01 12:37:25
【问题描述】:
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;
        }
    }
}

我正在使用此代码按属性名称对我的通用列表进行排序。当属性类型为string时,此代码运行成功,但当属性类型为longint时,出现此异常:

无法转换类型的对象 '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();

在上面一行中,我决定使用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;
}

我使用反射获得了 propertyType,但在 Func 中我不能像这样使用它:"Func&lt;TModel, propertyType&gt;" 有什么办法可以解决这个问题

感谢您的帮助。

【问题讨论】:

  • 没有时间去寻找错误,但你应该可以从这里窃取大部分 lambda 代码:stackoverflow.com/questions/41244/dynamic-linq-orderby - 非常相似的问题
  • 另外,using dynamic = System.Linq.Dynamic; 真的很混乱; dynamic 是上下文关键字;强烈建议您选择另一个别名...或者根本不使用别名
  • "使用动态 = System.Linq.Dynamic;"我删除了这个。我改变了“var e1 = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p1 }, null, exp1);”感谢您的建议

标签: c# linq reflection dynamic


【解决方案1】:

它不起作用的原因确实是拳击,正如另一个答案中提到的那样。

class S
{
  public int f;
  public S s;
}

{
  Func<S, S> sGetter = s => s.s; // okay
  Func<S, object> objectGetter = s => s.s; // okay
  objectGetter = sGetter; // also okay
}

{
  Func<S, int> intGetter = s => s.f; // okay
  Func<S, object> objectGetter = s => s.f; // still okay
  objectGetter = intGetter; // not okay
}

Func&lt;S, object&gt; objectGetter = s =&gt; s.f 有效但最后一个分配无效的原因是它实际上被解释为Func&lt;S, object&gt; objectGetter = s =&gt; (object)s.f,并且该强制转换执行了实际操作。 intGetterobjectGetter 不做同样的事情,因此不能将一个重新解释为另一个。意识到这一点,如果您自己包含该演员表,您应该没问题。据我所知,如果您简单地指定所需的返回类型为object,DQL(这就是您正在使用的,对吗?)将为您执行此操作:

var e1 = DynamicExpression.ParseLambda(new[] { p1 }, typeof(object), exp1);

【讨论】:

    【解决方案2】:

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

    您实际上可以使用返回该属性的 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;
    }
    

    请注意,我已将 Func 委托包装到 Expression 类型中(您可能想要 read more 了解它)。这样,我可以询问表达式并找出它使用了哪些成员。当然,除了简单的x =&gt; x.Property lambdas 之外,这将失败,因此您可能需要进行一些错误检查。

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

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

    实际用法可能如下所示:

    List<Foo> foos = ... ;
    foos.SortForMe(x => x.IntegerProperty, SortDirection.Ascending);
    foos.SortForMe(x => x.StringProperty, SortDirection.Ascending);
    

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

    【讨论】:

    • 我不能在方法参数中使用 lamda。只是,我知道属性名称是字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-13
    • 2020-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多