-1

、などを持つコンボボックスからstring Qty、およびデータベース列を持つことになるフォームがあります。オプションごとに ifelse/switch ステートメントを記述せずに、LINQ 式内でこれを評価する方法を見つけようとしています。string SelectedQtyOperator>==<=?intQty

現在私は持っています:

data = data.Where(m => Convert.ToInt32(m.Qty) [somehow evaluate SlQtyOp] Convert.ToInt32(Qty)).Select(m => m);

式の中でこれを行うこと、またはそれを評価して適切な式を返す何らかのタイプのヘルパー関数を持つことは可能ですか?

編集:

言及するのを忘れていましたが、次のようdataに初期化されます:

var data = db.MyDatabase.Select(m => m);

ここで、db は DataContext です

LINQ-to-Object を使用し、これを読んでいる方へ

私はLINQ-to-SQLでこれを実行しようとしていましたが(私自身の過失により、最初は言及しませんでした)、Jim MischelSriram Sakthivelが、役立つ可能性のあるさまざまなソリューションを投稿しました。

4

5 に答える 5

4

私はこのようなことをします:

bool IsLessThan(int a, int b)
{
    return a < b;
}

bool IsGreaterThan(int a, int b)
{
    return a > b;
}

IsEqualIsLessEqualIsGreaterEqualを同様に作成IsNotEqualします。

デリゲートを作成します。

Func<int, int, bool> comparisonFunc;

LINQ を呼び出す前に、デリゲートを割り当てます。

switch (oper)
{
    case "<" : comparisonFunc = IsLessThan; break;
    case ">" : comparisonFunc = IsGreaterThan; break;
    // etc.
}

LINQ 式は次のようになります。

data = data.Where(m => comparisonFunc(m.Qty, Convert.ToInt32(Qty))).Select(m => m);

ここで、フィールドのint一部が 、一部がdoubleなどの場合、メソッドはわずかに異なります。

bool IsLessThan(int rslt)
{
    return rslt < 0;
}

bool IsGreaterEqual(int rslt)
{
    return rslt >= 0;
}

等々。あなたのデリゲートは少し異なります:

Func<int, bool> comparisonFunc;

そしてIComparer、LINQ 式の型に を使用します。

data = data.Where(m => comparisonFunc(m.Qty.CompareTo(Convert.ToInt32(Qty)))).Select(m => m);

または、次の場合double:

data = data.Where(m => comparisonFunc(m.Qty.CompareTo(Convert.ToDouble(Qty)))).Select(m => m);

ちなみに、この場合は必要ありませんSelect。投影を行っていない (つまり、オブジェクトをそのまま取っている) ため、Select.

于 2013-10-29T19:29:33.123 に答える
1

if-elseorがないswitchと、LINQ ではできません。Dynamic LINQが必要になります。

于 2013-10-29T19:24:12.767 に答える
1

追加のライブラリを使用する必要のないタスクを処理する簡単な方法の 1 つは、クエリを部分的に構築することです。まず、テーブルをクエリし、他のWhere句を追加することから始めます。その後、次のswitchような簡単なステートメントを作成します。

IQueryable<MyDataType> data = ... // Put the initial query/table here
var qty = Convert.ToInt32(Qty);
switch (SelectedQtyOperator) {
    case ">": data = data.Where(m.Qty > qty ); break;
    case "<": data = data.Where(m.Qty < qty ); break;
    case "==": data = data.Where(m.Qty == qty ); break;
    case ">=": data = data.Where(m.Qty >= qty ); break;
    case "<=": data = data.Where(m.Qty <= qty ); break;
    default: /* Throw an exception: this shouldn't happen */ break;
}
foreach (var d in data) {
    ...
}
于 2013-10-29T19:27:47.887 に答える
0

したがって、これがIQueryableではなく のIEnumerable場合、関数ではなく式を操作する必要があります。まず、各演算子の文字列バージョンを含む辞書を定義し、それをその操作を表す式にマップします。

var mappings = new Dictionary<string, Expression<Func<int, int, bool>>>()
{
    {">", ( Expression<Func<int, int, bool>>)((a,b)=> a > b)},
    {"<", ( Expression<Func<int, int, bool>>)((a,b)=> a < b)},
    {"==", ( Expression<Func<int, int, bool>>)((a,b)=> a == b)},
};

他の操作を追加できます。

ある式全体で、ある式のすべてのインスタンスを別のインスタンスに置き換えるために使用するヘルパー メソッドもあります。

このビジターを使用します。

public class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

そして、それをよりクリーンな構文でラップするだけです:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

そこから問題の核心に移り、特定の演算子を使用して 2 つの特定のオペランドが評価される特定のクエリをフィルター処理する操作を作成します。フィルタリングするクエリ、各オペランドのセレクター、そして操作が必要です。次に、操作のパラメーターのすべてのインスタンスをオペランド セレクターに置き換え、右のセレクターのパラメーターを左のセレクターのパラメーターに置き換えます。これにより、最終製品に 1 つの実際のパラメーターが存在し、ラムダにラップされて渡されます。にWhere:

public static IQueryable<TIn> WhereOperator<TIn, TLeft, TRight>(
    this IQueryable<TIn> query,
    Expression<Func<TIn, TLeft>> leftSelector,
    Expression<Func<TIn, TRight>> rightSelector,
    Expression<Func<TLeft, TRight, bool>> operation)
{
    var newRightBody = rightSelector.Body.Replace(rightSelector.Parameters[0],
        leftSelector.Parameters[0]);
    var newOperator = operation.Body.Replace(operation.Parameters[0], leftSelector.Body)
        .Replace(operation.Parameters[1], newRightBody);
    var lambda = Expression.Lambda<Func<TIn, bool>>(newOperator,
        leftSelector.Parameters[0]);
    return query.Where(lambda);
}

使用例:

IQueryable<Tuple<int, int>> query = new[] { Tuple.Create(1, 2) }
    .AsQueryable();

var query2 = query.WhereOperator(pair => pair.Item1, pair => pair.Item2
    , mappings[">"]);

この場合、メモリ内クエリ可能オブジェクトを使用していますが、後で説明query2.Expressionするように、これは実際には以下を呼び出した場合と同じように見えます。

var query3 = query.Where(pair => pair.Item1 > pair.Item2);
于 2013-10-29T21:30:37.223 に答える
0

リフレクションで何かをすることは可能だと思いますが、次のようなこともできます:

switch (SlQtyOp)
{
case ">":
    data = data.Where(m => m.Qty > Convert.ToInt32(Qty)).Select(m => m);
case "<":
    data = data.Where(m => m.Qty < Convert.ToInt32(Qty)).Select(m => m);
case "=":
    data = data.Where(m => m.Qty = Convert.ToInt32(Qty)).Select(m => m);
}

ただし、スイッチを使用するのがおそらく最も簡単です。

于 2013-10-29T19:29:46.133 に答える