2

式ツリーで次のクエリを作成したい:

var test = from datarow in tempResults
           where datarow.Field<String>("ColumnName") == "Column"
           select datarow;

式の作成方法:

datarow.Field<String>("ColumnName")?

私はすべてを試しましたが、Expression.Call メソッドの Field の MethodInfo を取得することさえできませんでした。フィールドは、DataRowExtentions の拡張メソッドです。

これには Expression.Call() を使用する必要がありますか? MethodInfo を取得するにはどうすればよいですか? それを行う簡単な方法はありますか?

私は試した :

ParameterExpression dataRow = Expression.Parameter(typeof(DataRowExtensions), "dataRow"); Expression left = Expression.Call(dataRow, typeof(DataRowExtensions).GetMethod("Field"));

しかし、うまくいきません。


IQueryable tempResults 内のデータに対して動的フィルターを作成したいと考えています。

ユーザーは、tempResults のデータに「Where」式を追加する GUI のチェックボックスをオンにします。ユーザーが「Column」を選択すると、ColumnName = "Column" の DataRows を提示したいと考えています。

そのため、where 式を作成する必要があります。しかし、私は MethodInfo のことにとてもこだわっています。私もこれを試しました:

MethodInfo FieldStringMethodInfo = typeof(DataRowExtensions).GetMethod("Field", BindingFlags.Public | BindingFlags.Static);

しかし、それも機能しません。

それを行う他の方法はありますか?

4

1 に答える 1

2

コメントでの説明に続く代替回答:

追加のフィルターを連続して作成する場合、式ツリーは必要ありません。複数回呼び出すことができます.Where(必要に応じて、検索用語ごとに 1 回)。たとえば、次のようになります。

IEnumerable<DataRow> query = tempResults.AsEnumerable();
if(!string.IsNullOrEmpty(value1)) {
    query = query.Where(row => row.Field<string>("Col1") == value1);
}
if (!string.IsNullOrEmpty(value2)) {
    query = query.Where(row => row.Field<string>("Col2") == value2);
}

注意すべき唯一のことは、「キャプチャ」の問題です。などを再利用しないでくださいvalue1-value2そうしないと、最後の値が以前のフィルターに適用されます...


デリゲートの組み合わせの例 (コメントから) -DataTable例を短くするために、ここで側面を削除したことに注意してください (同じように機能します)。

public static class Predicate {
    public static Func<T, bool> OrElse<T>(
            this Func<T, bool> lhs, Func<T, bool> rhs) {
        return lhs == null ? rhs : obj => lhs(obj) || rhs(obj);
    }
    public static Func<T, bool> AndAlso<T>(
            this Func<T, bool> lhs, Func<T, bool> rhs) {
        return lhs == null ? rhs : obj => lhs(obj) && rhs(obj);
    }
}
class Data {
    public string Color { get; set; }
}
class Program {
    static void Main() {
        bool redChecked = true, greenChecked = true; // from UI...
        List<Data> list = new List<Data>() {
            new Data { Color = "red"},
            new Data { Color = "blue"},
            new Data { Color = "green"},
        };
        Func<Data, bool> filter = null;
        if (redChecked) {
            filter = filter.OrElse(row => row.Color == "red");
        }
        if (greenChecked) {
            filter = filter.OrElse(row => row.Color == "green");
        }
        if (filter == null) filter = x => true; // wildcard

        var qry = list.Where(filter);

        foreach (var row in qry) {
            Console.WriteLine(row.Color);
        }
    }
}

(元の回答)

実際、LINQ のそのバリアントは式ツリーを使用しません...デリゲートを使用します。しかし、本当に必要な場合は、ツリーを構築してコンパイルすることができます...なぜそうなるのかはわかりません。何をしたいですか?例を上げます...


どうぞ; これは式ツリーを使用していますが、できることを証明する以外に、これを行う正当な理由が 1 つも思いつきません!

public static class MyExtensions
{
    public static IQueryable<TRow> Where<TRow, TValue>(
        this IQueryable<TRow> rows,
        string columnName, TValue value)
        where TRow : DataRow
    {
        var param = Expression.Parameter(typeof(TRow), "row");
        var fieldMethod = (from method in typeof(DataRowExtensions).GetMethods()
                           where method.Name == "Field"
                           && method.IsGenericMethod
                           let args = method.GetParameters()
                           where args.Length == 2
                           && args[1].ParameterType == typeof(string)
                           select method)
                           .Single()
                           .MakeGenericMethod(typeof(TValue));
        var body = Expression.Equal(
            Expression.Call(null,fieldMethod,
                param,
                Expression.Constant(columnName, typeof(string))),
            Expression.Constant(value, typeof(TValue))
        );
        var lambda = Expression.Lambda<Func<TRow, bool>>(body, param);
        return rows.Where(lambda);

    }
}
class Program
{
    static void Main(string[] args)
    {
        DataTable tempResults = new DataTable();
        tempResults.Columns.Add("ColumnName");
        tempResults.Rows.Add("foo");
        tempResults.Rows.Add("Column");

        var test = tempResults.AsEnumerable().AsQueryable()
                   .Where("ColumnName", "Column");
        Console.WriteLine(test.Count());

    }
}
于 2009-08-23T12:52:41.530 に答える