3

LINQクエリでexpandoobjectsを使用して、実行時に作成されるプロパティ(csvファイルのヘッダーなど)に対してクエリを実行できるようにしました。例のように、コードにLINQクエリを直接入力すると、すべて正常に機能しました。

// initialize testdata
List<ExpandoObject> hans = new List<ExpandoObject>();
string[] names = {"Apfel", "Birne", "Banane", "Orange"};
int[] ids = { 1, 2, 3, 4 };
for (int i = 0; i < 4; i++)
{
   dynamic horst = new ExpandoObject();
   ((IDictionary<string, object>)horst).Add("Fruit", names[i]);
   ((IDictionary<string, object>)horst).Add("ID", ids[i]);
   hans.Add(horst);
}

// try some LINQ queries, both are working as intended
var klaus = from dynamic x in hans where x.ID < 3 select x;
//var klaus = hans.Where(x => x.ID < 3).Select(x => x);

次に、コマンドラインからクエリを読み取り、わずかに変更されたバージョンの評価用linqコンパイラを使用して動的LINQクエリを作成しようとしました。

string expression = System.Console.ReadLine();
LinqCompiler lc = new LinqCompiler(expression);
lc.AddSource<ExpandoObject>("hans", hans);
IEnumerable<ExpandoObject> klaus = (IEnumerable<ExpandoObject>)lc.Evaluate();

WHEREまたはORDERBYステートメントを使用しない限り、すべて問題ありませんが、WHEREまたはORDER BYがクエリに含まれていると、linqコンパイラでcodedomコードをコンパイルするときにエラーが発生します。CS1963:式ツリーには動的操作が含まれていない可能性があります。

クエリのコードは、次の行を使用して作成されます。

doRequestMethod.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(Query)));

codedomコンパイラは、LINQクエリで直接入力されたものが解析される方法とは異なる方法で式ツリーを構築していると思います。これを機能させるためのアイデアは、実行時に生成されたオブジェクトのクエリを動的に作成するための他のアイデアを含めて、評価されます。

4

1 に答える 1

2

取得しているエラーを取得するには、C# 4.0 を使用し、Microsoft.CSharp.dll への参照を追加するように指示することで、 LINQ コンパイラをサポートするように修正する必要がありました。dynamic

問題は、LINQ コンパイラのソースが を含む任意のコレクションになる可能性があることIQueryable<T>です。が正しく動作するはずであれば、実際にはではなくIQueryable<T>として扱う必要があります。LINQ コンパイラがこれを解決する方法は、拡張メソッドを使用してソースを扱うことです。IQueryable<T>IEnumerable<T>IQuerybale<T>AsQueryable()

これは、生成されたコードが次のようになることを意味します。

public object DoRequest(System.Linq.IQueryable<System.Dynamic.ExpandoObject> hans) {
    return from dynamic x in hans where x.ID < 3 select x;
}

このコードの問題は、 sIQuerybale<T>を使用する LINQ メソッドのバージョンを使用しようとすることExpressionです。そして、エラー メッセージが示すように、Expressions は をサポートしていませんdynamic

これを修正する最も簡単な方法は、 を次のように変更するのではなく、 を使用するように LINQ コンパイラを変更することだと思いIEnumerable<T>ます。IQuerybale<T>AddSource()

public void AddSource<T>(string name, IEnumerable<T> source) 
{
    this.sources.Add(new SourceDescription(name, typeof(IEnumerable<T>), source));
}

もちろん、これはデータベース クエリではうまく機能しないことを意味しますが、dynamicとにかくデータベース クエリを機能させることはできません。

于 2012-04-11T17:35:00.073 に答える