3

DynamicLinqを使用したメモリ内フィルタリングが必要です。私のオブジェクトにはインデクサーしかありません:

public  object this[int index] { }

私のデータへのアクセスは次のようなものです:object [0]、object [1]、..。

したがって、私のクエリは次のようになります。

// get FilterText from user at runtime
// eg. filterText can be: [0] > 100 and [1] = "wpf"
collection.AsQueryable().where(filterText);

これを行う方法はありますか?

4

3 に答える 3

2

お知らせがあります。

それは実際に可能です...しかし!(はい、ありますが)。

動的Linqライブラリを使用していると思います。次に、「it」キーワードを使用して、インデックス作成操作を適用する現在のオブジェクトを指定できるようにする必要があります。

ただし...インデクサーの戻りデータ型はオブジェクトであるため、データ型が一致しないため、[0]>100および[1]="wpf"と書き込むことはできません。

また、DynamicObjectから派生し、実行時にプロパティを追加する場合でも、それらのプロパティは、現在の状態の動的linqライブラリによって実行時に解決されません。フィールドを取得するか、プロパティがタイプxxxに存在しません。

これにはいくつかの解決策があり、そのうちのいくつかは解決策として受け入れることができます。

  • 醜い解決策の1つは、データ型の数が限られている場合、たとえばn(n <.NETの型の数)の場合、パラメーターが一致するn個のインデクサーを使用して、必要なデータ型を取得できます。たとえば、主にintといくつかの文字列がある場合:

    it[0] > 100 AND it[1, "dummy"] = "wpf" //The dummy parameter allows you to specify return type.
    
  • もう1つの醜い解決策であるDynamicLinqは、ToString()メソッドとConvertメソッドの使用をサポートしているため、たとえば、上記と同じクエリを記述できます。

    Convert.ToDouble(it[0]) > 100 AND it[1].ToString() = "wpf".
    
  • 3番目の醜い解決策は、データを変換する方法を指示する方法でステートメントをラップする規則を使用できます。たとえば、次のように書くことができます。

    it[0] > 100 AND it{1} = "wpf"
    

    そして、「it[」を「Convert.ToDouble(it[」などに置き換えます。

私が正しければ、ライブラリで汎用インデクサーを使用することもできないと思います。そして、Convert.ChangeTypeは、戻り型がまだオブジェクトであるため、この場合は役に立ちません。

たぶん私や他の誰かがこの種のことをサポートするためにいつかライブラリを書き直すでしょうが、近い将来(数週間)はそうする時間がありません。

申し訳ありませんが、15分以内にどこかに行かなければならないので、後でもっと良い解決策を講じる必要があります。

会議に自分をテレポートする

アップデート:

私はあなたの(そして私の)問題の解決策を見つけたかもしれないと思います!

DLINQライブラリでは、操作できるようにするタイプのメンバーをIxxxSignaturesインターフェースに追加できます。

そこで、(たとえば)IEqualitySignaturesに次のように追加しました。

void F(Object x, Int32 y);

そして、このようにelseブロックの(この場合)ParseComparisonメソッドを変更しました。

left = Expression.Convert(left, right.Type);

そして、信じられないかもしれませんが、うまくいきました:)

他のタイプや操作の署名を追加していないため、すべての種類の操作をテストしたわけではありませんが、実行するのは非常に簡単です。

アップデート

上記のいくつかのマイナーなものを更新しました。

私はこれについてもう少し実験しています。これも最も美しい解決策ではないかもしれませんが、次のようなことを行うことができます(DataObjectはインデクサーを備えた単なるDynamicObjectです)。

    [TestMethod]
    public void DynamicTest()
    {
        List<DataObject> dataObjects = new List<DataObject>();

        dynamic firstObject = new DataObject();
        dynamic secondObject = new DataObject();

        firstObject.dblProp = 10.0;
        firstObject.intProp = 8;
        firstObject.strProp = "Hello";

        secondObject.dblProp = 8.0;
        secondObject.intProp = 8;
        secondObject.strProp = "World";

        dataObjects.Add(firstObject);
        dataObjects.Add(secondObject);

        /* Notice the different types */
        string newQuery = FormatQuery("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'");

        var result = dataObjects.Where(newQuery);

        Assert.AreEqual(result.Count(), 1);
        Assert.AreEqual(result.First(), firstObject);
    }

そして、次のようなある種のフォーマットメソッド(完全なメソッドを作成したふりをします):

    public string FormatQuery(string query)
    {
        query = query.Replace('\'', '\"');

        string[] operators = new string[] { "<", ">", "!=", "<=", ">=", "<>", "=" };

        string[] parts = query.Split();

        for (int i = 0; i < parts.Length; i++)
        {
            if (operators.Contains(parts[i]))
            {
                parts[i - 1] = "it[\"" + parts[i - 1] + "\"]";
            }
        }

        return String.Join(" ", parts);
    }

もちろん、代わりに拡張メソッドを使用することもできます。

または...次のようなものを使用して、メソッドをDLINQ libに配置できます(ただし、良いアイデアとは言えません)。

if (typeof(T).GetInterface("IDynamicMetaObjectProvider", true) != null)
    whereClause = whereClause.FormatQuery();

そして、タイプが文字列インデクサーを実装しているかどうかを確認します。もちろん、次のようになります(ここではIndexerName属性を無視します)。

if (t.GetType().GetProperty("Item") != null)

これにより、「通常のユーザー」は次のように書くことができます。

data.Where("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'")

ええと、そこにそのようなものを入れるのは良くないかもしれませんが、あなたは要点を理解します。あなたが持つことができます!:)

于 2012-01-28T10:49:34.140 に答える
1

DynamicLinq http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspxを使用するか、式を作成します反射を使用するツリー。多くの人がこれにDynamicLinqライブラリを好みます。私はそれを自分で使ったことがなく、リフレクションアプローチを採用しました。

于 2012-01-28T03:36:37.737 に答える
1

DynamicLinq言語とC#でit同等のインデクサーを前に付ける必要があります。this

だから、あなたはただ必要it[1] == "wpf"です。

ただし、インデクサーがを返すため、さらに複雑になりますobject。クラスタイプ(を含むstring)の場合、DLinqは必要に応じてすべてをプロモートします。

ただし、intsのような値型の場合は、を実行する必要がありますInt32(it[0]) > 10

于 2012-01-28T14:43:17.003 に答える