2

我想構建一個具有不同輸入參數類型的表達式字典。我試圖存儲參數的類型,因爲後來我打算使用Reflection來發現類型上的方法。下面是創建字典中的代碼,我創建的條目添加到它的通用增加功能:如何將表達式<Func <T, bool>>轉換爲表達式<Func <Type, bool>>?

public class LoadEntityQuery : IQuery<LoadEntityQueryResult> 
{ 
    public IDictionary<Type, Expression<Func<Type, bool>>> Entities { get; set; } 
    public LoadEntityQuery() 
    { 
     Entities = new Dictionary<Type, Expression<Func<Type, bool>>>(); 
    } 

    public void Add<T>(Expression<Func<T, bool>> where = null) where T : Entity 
    { 
     Expression<Func<Type, bool>> _lambda = null; 

     if (where != null) 
     { 
      ParameterExpression param = Expression.Parameter(typeof(T), where.Parameters[0].Name); 

      var body = Expression.Invoke(where, param); 
      _lambda = Expression.Lambda<Func<Type, bool>>(body, param); 
     } 

     Entities.Add(typeof(T), _lambda); 
    } 
} 

新方法的主體正確創建。問題是當我嘗試創建新的Lambda表達式時,表達式的類型被傳入,我收到此錯誤:

類型'TestNamespace.TestClass'的ParameterExpression不能用於'System'類型的委託參數。類型'

有沒有人有一個想法,我可以在這種情況下做什麼?就像我之前說過的,稍後我會循環閱讀這本詞典,對每個條目做一些反思性編程。如果有更好的方法來做到這一點,我是全部耳朵。

至於是什麼,我試圖做一個例子,我存儲凡需要POCO對象的條款進行初始化表達式:

LoadEntityQuery _query = new LoadEntityQuery(); 
    _query.Add<PayrollLocation>(); 
    _query.Add<PayrollGroupBU>(); 
    _query.Add<PersonnelPosition>(t => t.DataSet == MasterDataSet); 
    _query.Add<EmployeeStatus>(); 
    _query.Add<PayrollGrade>(); 

實體的這份名單將是每個應用程序不同。這個想法是收集所有的實體和Where子句,並在每個實體上使用反射來發現某種方法。 (例如,PayrollLocation有一個GetPayrollLocationsQuery()方法,PayrollGroupBU有一個GetPayrollGroupBUQuery()方法...)。 Add方法是通用的,以便在調用代碼中使用lambda表達式。

感謝, 傑森

回答

4

仔細看看你的代碼,你生成的表達式有一些問題。在this answer頂部看到我的解釋來解釋其中的一個,這裏的問題是相同的。您正在創建一個新的lambda,其中您在此創建的參數實例未在正文中使用。

更大的問題是,您的表達式對於您似乎正在嘗試做的事情來說只是錯誤的。據我所知,你只是試圖創建一個從實體類型到採用該類型實體並返回一個bool的函數的映射。 Type -> Expression<Func<TEntity, bool>>。你構建的表達式不起作用。

您應該讓字典存儲非泛型lambda表達式,這樣您可以輕鬆地存儲這些函數,而無需執行轉換或重建表達式。您將無法將它們作爲通用lambdas存儲在此處。然後在訪問它們時轉換爲通用lambda。我把它放在一個單獨的類中來管理鑄造,並重構你的代碼到這個:

// add all necessary error checking where needed and methods 
public class EntityPredicateDictionary 
{ 
    private Dictionary<Type, LambdaExpression> dict = new Dictionary<Type, LambdaExpression>(); 

    public Expression<Func<TEntity, bool>> Predicate<TEntity>() where TEntity : Entity 
    { 
     return (Expression<Func<TEntity, bool>>)dict[typeof(TEntity)]; 
    } 

    public LambdaExpression Predicate(Type entityType) 
    { 
     return dict[entityType]; 
    } 

    internal void Add<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : Entity 
    { 
     dict.Add(typeof(TEntity), predicate); 
    } 
} 

public class LoadEntityQuery : IQuery<LoadEntityQueryResult> 
{ 
    public EntityPredicateDictionary Entities { get; private set; } 
    public LoadEntityQuery() 
    { 
     Entities = new EntityPredicateDictionary(); 
    } 

    public void Add<TEntity>(Expression<Func<TEntity, bool>> predicate = null) where TEntity : Entity 
    { 
     Entities.Add(predicate); 
    } 
} 

// then to access the predicates 
LoadEntityQuery query = ...; 
var pred1 = query.Entities.Predicate<Entity1>(); 
var pred2 = query.Entities.Predicate(typeof(Entity2)); 
+0

完美!謝謝傑夫 - 這是一個真正的幫助(正如你的其他職位)。我對LambdaExpressions有很多瞭解,對他們來說我還是比較陌生。感謝您的幫助。 – Rockdocta 2011-05-11 01:19:19

0

我不認爲這是要幹什麼你期望它做的事情; Func<Type, bool>定義了一個函數,它將一個類型作爲參數並返回一個bool。 Func<T, bool>定義了一個函數,它將T類型的對象作爲參數並返回一個布爾值。在你的字典中定義的lambda永遠不會接收你試圖過濾的對象,只有它的類型。

對我來說,以任何合適的方式做到這一點的最快方法是使LoadEntityQuery類通用於您希望函數接受的參數的類型,但這可能會限制您以其他方式...

你可以使用一個對象並將它轉換...不是最好的解決方案,但至少它封裝了鑄件並且是相當小的一塊,同時仍然允許你做我認爲你需要做的事情。

public class LoadEntityQuery : IQuery<LoadEntityQueryResult> 
{ 
    // Note: Hide this, we don't want anyone else to have to think about the cast. 
    private IDictionary<Type, object> Entities { get; set; } 

    public void Add<T>(Expression<Func<T, bool>> where = null) where T : Entity 
    { 
     Entities.Add(typeof(T), where); 
    } 

    public Expression<Func<T, bool>> Retrieve<T>() where T : Entity 
    { 
     if (!Entities.ContainsKey(typeof(T))) 
      return null; 
     return (Expression<Func<T, bool>>)Entities[typeof(T)]; 
    } 
} 
+0

我原本有這樣的設計 - 它在某些方面是有限制的。 – Rockdocta 2011-05-10 17:55:18

+0

@Rockdocta - 我已經添加了一個替代解決方案,也許它至少會給你一個想法嘗試。 – 2011-05-10 22:34:30

相關問題