English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
لقد تعرفت على التعبير في القسم السابق. دعونا نتعرف على شجرة التعبير هنا.
كما يوحي الاسم، فإن شجرة التعبير هي مجرد تعبيرات مرتبة بشكل شجري. كل عقدة في شجرة التعبير هي تعبير. على سبيل المثال، يمكن استخدام شجرة التعبير لتمثيل معادلة رياضية x < y، حيث سيتم تمثيل x، < و y كتعبيرات وترتب في بنية شجري.
شجرة التعبير هي شكل ذاكراتي لتعبير lambda. إنها تحفظ العناصر الفعلية للبحث وليس نتائج البحث.
تسمح شجرة التعبير بوضوح وتفاصيل بنية تعبير lambda. يمكنك التفاعل مع البيانات في شجرة التعبير كما تفعل مع أي هيكل بيانات آخر.
على سبيل المثال، انظر إلى تعبير isTeenAgerExpr التالي:
Expression<Func<Student, bool>> isTeenAgerExpr = s => s.age > 12 && s.age < 20;
المبرمج سيقوم بتحويل التعبير السابق إلى شجرة التعبير التالية:
مثال: شجرة التعبير في C#
Expression.Lambda<Func<Student, bool>>( Expression.AndAlso( Expression.GreaterThan(Expression.Property(pe, "Age"), Expression.Constant(12, typeof(int))), Expression.LessThan(Expression.Property(pe, "Age"), Expression.Constant(20, typeof(int)))), new[] { pe });
يمكنك أيضًا بناء شجرة التعبير يدويًا. لنرى كيف يمكننا بناء شجرة التعبير لتعبير lambda البسيط التالي:
مثال: وفد Func في C#:
Func<Student, bool> isAdult = s => s.age >= 18;
سيتم اعتبار نوع Func هذا الوفد كالتالي:
C#:
public bool function(Student s) { return s.Age > 18; }
لإنشاء شجرة التعبير، قم أولاً بإنشاء تعبير معلمات، حيث هو نوع المعلمات، و 's' هو اسم المعلمات، كما يلي:
خطوة 1: إنشاء تعبير معلمات في C#
ParameterExpression pe = Expression.Parameter(typeof(Student), "s");
الآن، استخدم Expression.Property() لإنشاء تعبير s.Age، حيث s هي المعلمات، وAge هو اسم الخاصية لـ Student.Expressionهي فئة أ抽象ة تحتوي على طرق مساعدة ثابتة لإنشاء شجرة التعبير يدويًا.)
خطوة 2: إنشاء تعبير خاصية في C#
MemberExpression me = Expression.Property(pe, "Age");
الآن، قم بإنشاء تعبير ثابت لعدد 18:
خطوة 3: إنشاء تعبير ثابت في C#
ConstantExpression constant = Expression.Constant(18, typeof(int));
حتى الآن، قمنا ببناء شجرة التعبير لتعبير s.Age (تعبير العضو) و 18 (تعبير الثابت). الآن، نحتاج إلى التحقق من أن تعبير العضو أكبر من تعبير الثابت. لهذا، استخدم دالة Expression.GreaterThanOrEqual()، وقدم تعبير العضو وتعبير الثابت كمعلمتين:
خطوة 4: إنشاء تعبير ثنائي في C#
BinaryExpression body = Expression.GreaterThanOrEqual(me, constant);
لذلك، قمنا ببناء شجرة التعبير لجسم تعبير lambda s.Age >= 18. الآن، نحتاج إلى ربط تعبير المعلمات وتعبير الجسم. باستخدام Expression.Lambda
خطوة 5: إنشاء تعبير Lambda في C#
var isAdultExprTree = Expression.Lambda<Func<Student, bool>>(body, new[] { pe });
بهذا، يمكنك بناء شجرة التعبير لـFunc بـlambda بسيط.
مثال: شجرة التعبير في C#
ParameterExpression pe = Expression.Parameter(typeof(Student), "s"); MemberExpression me = Expression.Property(pe, "Age"); ConstantExpression constant = Expression.Constant(18, typeof(int)); BinaryExpression body = Expression.GreaterThanOrEqual(me, constant); var ExpressionTree = Expression.Lambda<Func<Student, bool>>(body, new[] { pe }); Console.WriteLine("شجرة التعبير: {0}", ExpressionTree); Console.WriteLine("جسم شجرة التعبير: {0}", ExpressionTree.Body); Console.WriteLine("عدد الم参数 في شجرة التعبير: {0}", ExpressionTree.Parameters.Count); Console.WriteLine("الم 参数 في شجرة التعبير: {0}", ExpressionTree.Parameters[0]);
Dim pe As ParameterExpression = Expression.Parameter(GetType(Student), "s") Dim mexp As MemberExpression = Expression.Property(pe, "Age") Dim constant As ConstantExpression = Expression.Constant(18, GetType(Integer)) Dim body As BinaryExpression = Expression.GreaterThanOrEqual(mexp, constant) Dim ExpressionTree As Expression(Of Func(Of Student, Boolean)) =}} Expression.Lambda(Of Func(Of Student, Boolean))(body, New ParameterExpression() {pe}) Console.WriteLine("شجرة التعبير: {0}", ExpressionTree) Console.WriteLine("جسم شجرة التعبير: {0}", ExpressionTree.Body) Console.WriteLine("عدد الم参数 في شجرة التعبير: {0}", ExpressionTree.Parameters.Count) Console.WriteLine("الم参数 في شجرة التعبير: {0}", ExpressionTree.Parameters(0))
شجرة التعبير: s => (s.Age >= 18) جسم شجرة التعبير: (s.Age >= 18) عدد الم参数 في شجرة التعبير: 1 الم参数 في شجرة التعبير: s
الشكل التالي يوضح عملية إنشاء شجرة التعبير بالكامل:
في الفصل السابق، رأينا كيف يتم تخصيصFunc<T>يتم ترجمة إلى شفاء قابل للتنفيذ، وتُعين على التعبير lambdaExpression<TDelegate>تتم ترجمة النوع إلى شجرة التعبير.
يتم تنفيذ الشفاء في نفس مجال التطبيق لتعالجة المجموعات في الذاكرة. تحتوي الفئة الكونية القابلة للتنفيذ على أدوات لتحقيقIEnumerable <T>طرق extension للمجموعات في الذاكرة مثل List <T>،Dictionary <T> وما إلى ذلك. تقبل الطريقة extension في فئة EnumerableFuncالعمود المعرفي للإذن. على سبيل المثال،Whereيقبل الطريقة extensionpredicate للإذن <TSource،bool>ثم يتم تضمينها في IL (لغة وسطية) لمعالجة المجموعات في نفس AppDomain.
الشكل التالي يوضح كيف تشمل طريقة expansion في فئة Enumerable الإذن كمعامل:
Funcالإذن هو شفاء قابل للتنفيذ أصلًا، لذا إذا كنت ت调试 الشفاء، فإنك ستجد:Funcالإذن سيتم تمثيله كشفاء غير شفاف. لا يمكنك رؤية معاملاته، نوع العودة والموضوع:
Funcالممثل يستخدم في المجموعات في الذاكرة، لأنه سيتم معالجته في نفس AppDomain، ولكن ماذا عن بروتوكولات LINQ-to-SQL، EntityFramework أو منتجات ثالثة أخرى التي توفر LINQ مثل بروتوكولات الاستعلام LINQ البعيدة؟ كيف سيتم تحليلهم للممثلات lambda التي تم ترميزها إلى كود قابل للتنفيذ الأصلي لفهم المعامل، نوع العودة للممثل lambda، والبناء على الاستعلام التشغيلي لمعالجة المزيد؟ الإجابة هيشجرة التعبير.
Expression <TDelegate> يتم ترميزه إلى بنية بيانات تسمى شجرة التعبير.
إذا تم ت调试 الكود، فإن التعبير يمثل ما يلي:
الآن يمكنك رؤية الفرق بين الممثل العادي وشجرة التعبير. شجرة التعبير شفافة. يمكنك استخراج معلومات مثل المعامل، نوع العودة، والجسم التعبيري من التعبير، كما هو موضح أدناه:
Expression<Func<Student, bool>> isTeenAgerExpr = s => s.Age > 12 && s.Age < 20; Console.WriteLine("Expression: {0}", isTeenAgerExpr); Console.WriteLine("نوع التعبير: {0}", isTeenAgerExpr.NodeType); var parameters = isTeenAgerExpr.Parameters; foreach (var param in parameters) { Console.WriteLine("اسم المعامل: {0}", param.Name); Console.WriteLine("نوع المعامل: {0}", param.Type.Name); } var bodyExpr = isTeenAgerExpr.Body as BinaryExpression; Console.WriteLine("الجانب الأيسر من التعبير: {0}", bodyExpr.Left); Console.WriteLine("نوع التعبير الثنائي: {0}", bodyExpr.NodeType); Console.WriteLine("الجانب الأيمن من التعبير: {0}", bodyExpr.Right); Console.WriteLine("نوع العودة: {0}", isTeenAgerExpr.ReturnType);
تعبير: s => ((s.Age > 12) AndAlso (s.Age < 20)) نوع التعبير: Lambda اسم المعامل: s نوع المعامل: Student الجانب الأيسر من جسم التعبير: (s.Age > 12) نوع التعبير الثنائي: AndAlso الجانب الأيمن من جسم التعبير: (s.Age < 20) نوع العودة: System.Boolean
لا تنفذ استعلامات LINQ لـ LINQ-to-SQL أو Entity Framework في نفس منطقة التطبيق. على سبيل المثال، لن يتم تنفيذ LINQ التالي لـ Entity Framework في الداخل فعليًا:
var query = from s in dbContext.Students where s.Age >= 18 select s;
أولاً، قم بتحويله إلى جملة SQL، ثم أجره على خادم قاعدة البيانات.
يجب تحويل الكود الموجود في تعبيرات الاستعلام إلى استعلام SQL، يمكن إرساله كنص إلى عملية أخرى. بالنسبة لـ LINQ-to-SQL أو Entity Framework، يكون ذلك عملية SQL Server. تحويل بنية البيانات (مثل شجرة التعبيرات) إلى SQL أسهل بكثير من تحويل IL أو كود قابل للتنفيذ الأصلي إلى SQL، لأنه كما ترون، من السهل استخراج المعلومات من التعبير.
يتم إنشاء شجرة التعبيرات لتحويل كود مثل تعبيرات الاستعلام إلى سلسلة نصية يمكن نقلها إلى عملية أخرى وإجراؤها هنا.
الصفحات الثابتة القابلة للبحث تشمل الطرق الموسعة التي تأخذ كائن Expression كمعامل شرط. يتم تحويل هذا تعبير الشرط إلى شجرة تعبيرات، ثم يتم نقلها كنوع بيانات إلى مقدم LINQ الموجود على بعد، حيث يمكن للمقدم من بناء استعلام مناسب من شجرة التعبيرات واستدعاء الاستعلام.