式を変換する方法 >〜式 >?

expression-trees functional-programming generics linq reflection

質問

私はさまざまな入力パラメータの種類を持つ式の辞書を構築しようとしています。私はパラメータの型を保存しようとしています。後で、Reflectionを使用してその型のメソッドを発見することを計画しています。辞書を作成するコードと、それにエントリを追加するために作成した汎用のAdd関数です:

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

新しいメソッドの本体が正しく作成されます。問題は、渡される式の型で新しいラムダ式を作成しようとするときです。このエラーが発生します。

型 'System.Type'の代行パラメータに 'TestNamespace.TestClass'型のParameterExpressionを使用することはできません

誰も私がこのような状況でできることについて考えているのですか?私が前に言ったように、ある時点で、この辞書をループして、各エントリで反射的プログラミングを行うつもりです。これを行うより良い方法があれば私はすべての耳です。

私が何をしようとしているかの例として、初期化が必要な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メソッドは、呼び出しコードでラムダ式を使用するために汎用的です。

ありがとう、ジェイソン

受け入れられた回答

コードを詳しく見てみると、生成する式にはいくつかの問題があります。 この答えの一番上にある私の説明を参照して、その1つを説明してください。これは同じ問題です。ここで作成したパラメータインスタンスが本体で使用されていない新しいラムダを作成しています。

より大きな問題は、あなたがしようとしていると思われるものに対して、あなたの表現が間違っていることです。私が知る限り、エンティティ型からその型のエンティティを取得してboolを返す関数へのマッピングを作成しようとしているだけです。 Type -> Expression<Func<TEntity, bool>>あなたが構築する表現はうまくいきません。

辞書ストアに非汎用ラムダを作成して、式の変換や再構築を行わずにこれらの関数を簡単に保存できるようにする必要があります。ここでは一般的なラムダとして保存することはできません。次に、それらにアクセスするときに一般的なラムダにキャストします。私は鋳造とリファクタリングあなたのコードを管理する別のクラスにこれを置く:

// 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を返す関数を定義します。あなたの辞書に定義されているラムダは、フィルタリングしようとしているオブジェクトを決して受け取らず、その型だけを受け取ります。

私には、これを適切な方法で行うための最も速い方法は、あなたの関数が受け入れることを期待するパラメータの型に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は合法ですか? はい、理由を学ぶ