如何轉換錶達式 >表達 >?

expression-trees functional-programming generics linq reflection

我正在嘗試構建具有不同輸入參數類型的表達式字典。我試圖存儲參數的類型,因為後來我計劃使用Reflection來發現類型的方法。下面是創建字典的代碼和我創建的通用添加函數,用於向其添加條目:

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.Type”類型的委託參數

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

作為我想要做的一個例子,我存儲了需要初始化的POCO對象的Where子句的表達式:

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表達式。

謝謝你,傑森

一般承認的答案

仔細查看代碼,您生成的表達式存在一些問題。請參閱本答案頂部的解釋來解釋其中一個問題,這是同一個問題。您正在創建一個新的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));

熱門答案

我不認為這會做你期望它做的事情; Func<Type, bool>定義一個函數,該函數將一個類型作為參數並返回一個bool。 Func<T, bool>定義一個函數,該函數將類型為T的對像作為參數並返回bool。字典中定義的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)];
    }
}


許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因