CヒドイIQueryableは、式樹の神秘的なベールをはがします。
13395 ワード
木は何ですか?
木は何ですか?この問題はちょっと白痴のようです。木は木じゃないですか?
私たちは一番下の主幹から上を見ます。主枝-分岐-分岐…無限の分岐と言えます。私たちは逆を見てみます。
普段一番多く使われているツリー構造のデータはXMLです。ノードの下には無限にサブノードを追加できます。私達は普段またどんな木の構造のデータを使ったことがあるかを考えてみます。
今日話したのと関係がありますね。今日は主に表現ツリーを分析します。
lamda表現と表現ツリーの違い:
Lamda表現:
最初のlamda表現は匿名関数にコンパイルされ、第二の表現ツリーは私たちの知らないものの山にコンパイルされています。私たちが以前書いたlamdaよりずっと複雑です。
結論:
私たちが普段使っている表式ツリーは、lamda表式を作成してコンパイルした表式ツリーです。つまり、一般的に使われている表式ツリーはコンパイラで作ってくれます。もちろん、我々は手動でアクティブに表現ツリーを作成することができます。ただ面倒臭いだけで、必要な状況ではないです。誰がこの苦しい仕事をやりたいですか?)
式樹には何か不思議なところがありますか?
ちょっと見た感じがしますか?BodyにはRight、Leftがあります。RightにはRight、Leftがあります。それらのタイプはすべてExpressionから継承されています。このようなノードの下にノードがあり、無限に添付できるデータ構造をツリー構造データと呼びます。つまり私たちの表現ツリーです。
補足:上のStudentエンティティ類:
上にはいわゆる表式の木を見ましたが、他にも思ったほど複雑ではありません。木の構造データじゃないですか?私たちが自分のormを実現するには、式樹を解析する必要があります。解析ツリー構造データといえば、再帰的アルゴリズムが使われます。解析式ツリーを開始します。
解析方法を先に定義します。
基本的に私たちが欲しい元素と値は全部取りました。どうやって組み立てるかはあなたの気持ち次第です。sqlにするか、それとも生成urlにするか、どうぞご自由に!
自分のIQueryable、IQueryProviderを実現します。
式樹を解析しただけで、自分のormを叩くことができますか?駄目です。少なくともIQueryableインターフェースに基づいてエンコードします。
次に私達はカスタムクラスのMyQueryableインターフェースIQueryable:
IQueryable<T>とExpression(表現ツリー)の関係が分かりましたね。
IQueryable<T>の最も主要な役割は、Expression(式樹)を記憶することです。
私達もカスタムしました。IQueryProviderインターフェースの種類MyQueryProvider:毎回Whereクエリを実行するとIQueryProviderが新しいIQueryable を作成してくれます。 AsEnumerableメソッドを呼び出したときは、実際に値を取ることはありません。 ToList()メソッドを実行した時、本当にローズデージェネレータGetEnumerator()を呼び出します。 本当に値を取る時は、IQueryProviderのExecuteメソッドを実行します。この方法を呼び出したときに式の数を解析し、取得結果を実行することです。
私達は本当に事実を行うべきExecuteを見ましたが、彼をデフォルトに戻しました。
今は嫌な人がいるかもしれません。具体的にExecuteを実現してください。はい上記の解析式樹を通して、ここでやりたいことを自分でやってもいいです。)
まず簡単のために、集合をデータソースにします。
個人のIQueryable遅延負荷に対する理解: 前の部分のクエリオペレータは、論理分解を式樹に格納するだけで、リモートでsqlを実行していません。 foreacheはIEnumerable<T>を実行するが、IEnumerable<T>は同様に遅延負荷の特性を有する。反復する度にデータを取ります。また、ナビゲーション属性を使用すると、再度データベースを検索します。今度は遅延ロードと言ってIEnumerableの功労を忘れないでください。) 豆知識:
式ツリーをLamda式に変換します。
表式ツリーの分析が一段落しました。まだ多くの詳細があります。または重要なことは分析されていません。次回は新しい心得があります。
感覚表式ツリーとは、まず表式をツリー構造に散在させて(一般的には散逸の過程でコンパイラが完了します)、その後、異なるデータソースやインターフェースによって自分の欲しい形式に再編成することができます。これも自分のormを可能にします。
今日は主に表現ツリーの解析と、自分を実現するIQueryableとIQueryProviderに対して記録とまとめを行いました。中には間違った結論や言い方があるかもしれません。軽く撮ります。
以上はC萼IQueryable<T>式樹の神秘的なベールの詳細を明らかにしました。C〓IQueryable<T>に関する資料は他の関連記事に注目してください。
木は何ですか?この問題はちょっと白痴のようです。木は木じゃないですか?
私たちは一番下の主幹から上を見ます。主枝-分岐-分岐…無限の分岐と言えます。私たちは逆を見てみます。
普段一番多く使われているツリー構造のデータはXMLです。ノードの下には無限にサブノードを追加できます。私達は普段またどんな木の構造のデータを使ったことがあるかを考えてみます。
今日話したのと関係がありますね。今日は主に表現ツリーを分析します。
lamda表現と表現ツリーの違い:
Lamda表現:
Func<Student, bool> func = t => t.Name == " ";
式ツリー:
Expression<Func<Student, bool>> expression = t => t.Name == " ";
どう見ても、違いはないですね。式はExpressionで包んだだけです。それは間違っています。これはMicrosoftが見せてくれたカムフラージュです。コンパイルされたC((zhi)コードを見ます。最初のlamda表現は匿名関数にコンパイルされ、第二の表現ツリーは私たちの知らないものの山にコンパイルされています。私たちが以前書いたlamdaよりずっと複雑です。
結論:
私たちが普段使っている表式ツリーは、lamda表式を作成してコンパイルした表式ツリーです。つまり、一般的に使われている表式ツリーはコンパイラで作ってくれます。もちろん、我々は手動でアクティブに表現ツリーを作成することができます。ただ面倒臭いだけで、必要な状況ではないです。誰がこの苦しい仕事をやりたいですか?)
式樹には何か不思議なところがありますか?
ちょっと見た感じがしますか?BodyにはRight、Leftがあります。RightにはRight、Leftがあります。それらのタイプはすべてExpressionから継承されています。このようなノードの下にノードがあり、無限に添付できるデータ構造をツリー構造データと呼びます。つまり私たちの表現ツリーです。
補足:上のStudentエンティティ類:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Sex { get; set; }
}
解析式ツリー上にはいわゆる表式の木を見ましたが、他にも思ったほど複雑ではありません。木の構造データじゃないですか?私たちが自分のormを実現するには、式樹を解析する必要があります。解析ツリー構造データといえば、再帰的アルゴリズムが使われます。解析式ツリーを開始します。
解析方法を先に定義します。
//
public static class AnalysisExpression
{
public static void VisitExpression(Expression expression)
{
switch (expression.NodeType)
{
case ExpressionType.Call://
MethodCallExpression method = expression as MethodCallExpression;
Console.WriteLine(" :" + method.Method.Name);
for (int i = 0; i < method.Arguments.Count; i++)
VisitExpression(method.Arguments[i]);
break;
case ExpressionType.Lambda://lambda
LambdaExpression lambda = expression as LambdaExpression;
VisitExpression(lambda.Body);
break;
case ExpressionType.Equal://
case ExpressionType.AndAlso://and
BinaryExpression binary = expression as BinaryExpression;
Console.WriteLine(" :" + expression.NodeType.ToString());
VisitExpression(binary.Left);
VisitExpression(binary.Right);
break;
case ExpressionType.Constant://
ConstantExpression constant = expression as ConstantExpression;
Console.WriteLine(" :" + constant.Value.ToString());
break;
case ExpressionType.MemberAccess:
MemberExpression Member = expression as MemberExpression;
Console.WriteLine(" :{0}, :{1}", Member.Member.Name, Member.Type.ToString());
break;
default:
Console.Write("UnKnow");
break;
}
}
}
コール解析方法:
Expression<Func<Student, bool>> expression = t => t.Name == " " && t.Sex == " ";
AnalysisExpression.VisitExpression(expression);
すべてのノードを遍歴するまで、1つの階層のサブノードに再帰する。最後の印刷効果は以下の通りです。基本的に私たちが欲しい元素と値は全部取りました。どうやって組み立てるかはあなたの気持ち次第です。sqlにするか、それとも生成urlにするか、どうぞご自由に!
自分のIQueryable
式樹を解析しただけで、自分のormを叩くことができますか?駄目です。少なくともIQueryable
次に私達はカスタムクラスのMyQueryable
public class MyQueryable<T> : IQueryable<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public Type ElementType
{
get { throw new NotImplementedException(); }
}
public Expression Expression
{
get { throw new NotImplementedException(); }
}
public IQueryProvider Provider
{
get { throw new NotImplementedException(); }
}
}
私達はその中にインターフェース属性IQueryProviderがあるのを見ました。このインターフェースの役割は大きいですね。主な役割はオペレータを検索する時にIQueryable<T>を再作成し、最後に遍歴した時にsql遠隔取得を実行します。また、Expression属性を見ました。IQueryable<T>とExpression(表現ツリー)の関係が分かりましたね。
IQueryable<T>の最も主要な役割は、Expression(式樹)を記憶することです。
私達もカスタムしました。IQueryProviderインターフェースの種類MyQueryProvider:
public class MyQueryProvider : IQueryProvider
{
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
throw new NotImplementedException();
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public object Execute(Expression expression)
{
throw new NotImplementedException();
}
}
上は全部自動的に生成された疑似コードです。具体的な実装を満たします。
public class MyQueryProvider : IQueryProvider
{
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new MyQueryable<TElement>(expression);
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
return default(TResult);
}
public object Execute(Expression expression)
{
return new List<object>();
}
}
public class MyQueryable<T> : IQueryable<T>
{
public MyQueryable()
{
_provider = new MyQueryProvider();
_expression = Expression.Constant(this);
}
public MyQueryable(Expression expression)
{
_provider = new MyQueryProvider();
_expression = expression;
}
public Type ElementType
{
get { return typeof(T); }
}
private Expression _expression;
public Expression Expression
{
get { return _expression; }
}
private IQueryProvider _provider;
public IQueryProvider Provider
{
get { return _provider; }
}
public IEnumerator GetEnumerator()
{
return (Provider.Execute(Expression) as IEnumerable).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
var result = _provider.Execute<List<T>>(_expression);
if (result == null)
yield break;
foreach (var item in result)
{
yield return item;
}
}
}
実行コード:
var aa = new MyQueryable<Student>();
var bb = aa.Where(t => t.Name == " ");
var cc = bb.Where(t => t.Sex == " ");
var dd = cc.AsEnumerable();
var ee = cc.ToList();
結論:私達は本当に事実を行うべきExecuteを見ましたが、彼をデフォルトに戻しました。
今は嫌な人がいるかもしれません。具体的にExecuteを実現してください。はい上記の解析式樹を通して、ここでやりたいことを自分でやってもいいです。)
まず簡単のために、集合をデータソースにします。
// Student
public static List<Student> StudentArrary = new List<Student>()
{
new Student(){Name=" ", Age=26, Sex=" ", Address=" "},
new Student(){Name=" ", Age=23, Sex=" ", Address=" "},
new Student(){Name=" - ", Age=25, Sex=" ", Address=" "}
};
次に、Visit Expressition 2を書き換える方法:(以前との違い:現在の目的は、Sqlまたは他のものに再組み立てるのではなく、式樹における表現を取ることです。)
public static void VisitExpression2(Expression expression, ref List<LambdaExpression> lambdaOut)
{
if (lambdaOut == null)
lambdaOut = new List<LambdaExpression>();
switch (expression.NodeType)
{
case ExpressionType.Call://
MethodCallExpression method = expression as MethodCallExpression;
Console.WriteLine(" :" + method.Method.Name);
for (int i = 0; i < method.Arguments.Count; i++)
VisitExpression2(method.Arguments[i], ref lambdaOut);
break;
case ExpressionType.Lambda://lambda
LambdaExpression lambda = expression as LambdaExpression;
lambdaOut.Add(lambda);
VisitExpression2(lambda.Body, ref lambdaOut);
break;
case ExpressionType.Equal://
case ExpressionType.AndAlso://and
BinaryExpression binary = expression as BinaryExpression;
Console.WriteLine(" :" + expression.NodeType.ToString());
VisitExpression2(binary.Left, ref lambdaOut);
VisitExpression2(binary.Right, ref lambdaOut);
break;
case ExpressionType.Constant://
ConstantExpression constant = expression as ConstantExpression;
Console.WriteLine(" :" + constant.Value.ToString());
break;
case ExpressionType.MemberAccess:
MemberExpression Member = expression as MemberExpression;
Console.WriteLine(" :{0}, :{1}", Member.Member.Name, Member.Type.ToString());
break;
case ExpressionType.Quote:
UnaryExpression Unary = expression as UnaryExpression;
VisitExpression2(Unary.Operand, ref lambdaOut);
break;
default:
Console.Write("UnKnow");
break;
}
}
方法Executeを再実現します。
public TResult Execute<TResult>(Expression expression)
{
List<LambdaExpression> lambda = null;
AnalysisExpression.VisitExpression2(expression, ref lambda);//
IEnumerable<Student> enumerable = null;
for (int i = 0; i < lambda.Count; i++)
{
// LambdaExpression Expression<Func<Student, bool>>
// Compile()
Func<Student, bool> func = (lambda[i] as Expression<Func<Student, bool>>).Compile();
if (enumerable == null)
enumerable = Program.StudentArrary.Where(func);// IEnumerable
else
enumerable = enumerable.Where(func);
}
dynamic obj = enumerable.ToList();//( : , sql , url 。)
return (TResult)obj;
}
実行プロセス:個人のIQueryable遅延負荷に対する理解:
式ツリーをLamda式に変換します。
Expression<Func<Student, bool>> expression = t => t.Name == " ";
Func<Student, bool> func = expression.Compile();
締め括りをつける表式ツリーの分析が一段落しました。まだ多くの詳細があります。または重要なことは分析されていません。次回は新しい心得があります。
感覚表式ツリーとは、まず表式をツリー構造に散在させて(一般的には散逸の過程でコンパイラが完了します)、その後、異なるデータソースやインターフェースによって自分の欲しい形式に再編成することができます。これも自分のormを可能にします。
今日は主に表現ツリーの解析と、自分を実現するIQueryable
以上はC萼IQueryable<T>式樹の神秘的なベールの詳細を明らかにしました。C〓IQueryable<T>に関する資料は他の関連記事に注目してください。