2012-08-03 83 views
4
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; 
     } 
    } 
} 

我正在使用此代碼按propertyName排序我的通用列表。當屬性類型爲string,這段代碼成功運行,但是當類型爲longint,我得到這個異常:無法使用Int64投射System.Func`2類型的對象

無法轉換 類型的對象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; 
} 

我使用屬性類型反映,在函數功能我不能這樣使用它了:"Func<TModel, propertyType>"有什麼辦法來解決這個問題

感謝您的幫助。

+0

沒有時間去錯誤狩獵,但你應該能夠從這裏竊取大部分lambda代碼:http://stackoverflow.com/questions/41244/dynamic-linq-orderby - 非常類似的問題 – 2012-08-03 12:59:23

+2

也',使用動態= System.Linq。動態;'真的很混亂; 'dynamic'是上下文關鍵字;強烈建議你選擇另一個別名...或者根本不要使用別名 – 2012-08-03 13:01:47

+0

「using dynamic = System.Linq.Dynamic;」我刪除了這個。我改變了「var e1 = System.Linq.Dynamic.DynamicExpression.ParseLambda(new [] {p1},null,exp1);」感謝您的建議 – 2012-08-03 13:14:54

回答

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

注意到我包裹Func代表到Expression類型(您可能想read more這件事)。這樣,我可以詢問表達式並找出它使用哪些成員。當然,除了簡單的x => x.Property lambda以外,這將會失敗,因此您可能需要進行一些錯誤檢查。

要使用它,你將不得不改變你的擴展方法一點:

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#的類型推斷在這裏非常好用。

+0

我不能在方法參數中使用lamda。只有,我知道屬性名稱爲字符串。 – 2012-08-04 12:11:59

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<S, object> objectGetter = s => s.f作品,但最後的分配不能工作是,它實際上被解釋爲Func<S, object> objectGetter = s => (object)s.f,並投進行實際操作。 intGetterobjectGetter不會做同樣的事情,所以不能被重新解釋爲另一個。意識到這一點,你應該沒問題,如果你包括你自己。據我所知,DQL(即你使用的是什麼,對不對?)會爲你做的,如果你只是指定你所需的返回類型爲object

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