Expression Trees - 1. daļa

29. septembra Microsoft Partneru Konferences laikā Klausoties B. Zaas lekciju par C# 3.0 jaunākajām un jocīgākajām iespējām, atcerējos par izteiksmju kokiem jeb veidu, kā no lambda izteiksmes iegūt datu struktūru, kas apraksta šo matemātisko izteiksmi. Bet nu par visu pēc kārtas.

Expression Tree ir veids ar kura palīdzību ir iespējams no izpildāma koda (piemēram, LINQ izteiksmes) iegūt datus. Šis paņēmiens ir ērts, lai no LINQ izteiksmes ģenerētu SQL izteiksmes, kas tiek izpildītas uz servera. Nedaudz aizskrēju pa priekšu. Tātad, sāksim ar pavisam vienkāršu izteiksmes koda izveidošanu:

 

Func<int, int, int> function = (a, b) => (a + b);

 

Augstāk minētajā piemērā ir 3 daļas:

  1. Func<T1, T2, TResult> deklarēšana;
  2. Vienādības operātors: =;
  3. Lambda izteiksme: (a, b) => (a +b);

 

Mainīgais function tagad norāda uz izpildāmu kodu, kas prot vienu ciparu pieskaitīt pie otra. Tas ir apmēram tas pats, kas uzrakstīt funkciju:

 

public int function(int a, int b)
{
    return a + b;
}

 

Funkciju vai lambda izteikmsi var izsaukt šādi:

 

int c = function(4, 4);

 

Augstāk mēs redzējām, kā mēs varam izveidot mainīgo, kas norāda uz izpildāmu kodu. No šī izpildāmā koda var iegūt datu struktūru, kas apraksta izteiksmi - izteiksmes koku. Jāpievieno ir System.Linq.Expressions vārdu telpa, lai piekļūtu nepieciešamajām bibliotekām.

 

Expression<Func<int, int, int>> expression = (a, b) => a + b;

 

Visual Studio 2008 piemēros var atrast Expression Tree Visualizer rīku, kas palīdz attēlot grafiski, kāda ir izteiksmu koka struktūra.

 

 

Lambda izteiksmēm ir speciāla Compile() metode, kas no datu struktūras pārvērst atpakaļ to izpildāmā kodā un to izpilda. Piemēram, koda rindiņa atgriezīs 8:

 

expression.Compile()(4, 4);

 

Kāpēc tad īsti ir nepieciešami šie izteiksmju koki? Viens no plašāk izmantojamajiem mērķiem ir LINQ izteiksmes translēšana uz SQL izteiksmi. Piemēram,

 

var query = from c in db.Customers
            where c.City == "London"
            select new { c.City, c.CompanyName };

 

uz

 

SELECT [t0].[City], [t0].[CompanyName]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[City] = @p0

 

Evaluējot tālāk domu par izteiksmju kokiem ienāca prātā, ka arī man būtu jāievēro Greenspun 10-tais programmēšanas likums: "Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified bug-ridden slow implementation of half of Common Lisp."

Radās ideja implementēt pavisam vienkāršas Lisp izteiksmes interpretatoru un izpildītāju. Tātad Lisp matemātiskās operācijas sākas ar operatoru pēc kura seko visi pārējie operandi. Apmēram šādi: (+ 4 4).

Ieejas parametru nolasīšanai izveidojam ciklu:

 

Interpreter interpreter = new Interpreter();
string input = null;

while (true)
{
    Console.Write("> ");
    input = Console.ReadLine();

    if (string.Compare(input, "(quit)", true) == 0)
    {
        break;
    }

    interpreter.Input = input;
    Console.WriteLine(interpreter.Compile());
}

 

Tālāk ir jāķeras klāt pie interpretatora izveides. Par cik pirmajā raksta daļā uzdevums ir pavisam vienkāršs un lai nebūtu jānodarbojas ar ieejas parametru pamatīgu ķidāšanu, tad neaizrausimies ar iekļauto operāciju izpildi, kādā no operandiem, piemēram, (+ 4 (* 2 2)).

Izveidojam kodu, kas mums sadala operāciju un operandus (pievēršam uzmanību, ka šajā alfa versijā ir pieejams tikai operācijas ar skaitļiem līdz desmit (10) to neieskaitot :). Lielāki skaitļi tiks atbalstīti nākamajā CTP versijā).

 

string expressionType = this.Input.Substring(1, 1);
string leftSideValue = this.Input.Substring(3, 1);
string rightSideValue = this.Input.Substring(5, 1);

 

Pēc tam ir nepieciešams izveidot mērķa izteiksmju kokam labo un kreiso pusi, t.i., parametrus, kuriem tiks pielietotas vērtības lambda izteiksmes izpildes laikā.

 

var left = Expression.Parameter(typeof(int), "l");
var right = Expression.Parameter(typeof(int), "r");

 

Atkarībā no operācijas ir nepieciešams izveidot attiecīgo izteiksmes ķermeni:

 

switch (expressionType)
{
    case "+":
        body = Expression.Add(left, right);
        break;
    case "-":
        body = Expression.Subtract(left, right);
        break;
    case "/":
        body = Expression.Divide(left, right);
        break;
    case "*":
        body = Expression.Multiply(left, right);
        break;
    case ">":
        body = Expression.GreaterThan(left, right);
        break;
    case "<":
        body = Expression.LessThan(left, right);
        break;
    default:
        throw new InvalidOperationException("Operator is not supported.");
}

 

Šeit gan ir jāatzīmē, ka attiecīgās operācijas izvēli nevar veikt kaut kā dinamiskāk - t.i., nepieciešamā operācija ir jāveido izsaucot attiecīgo statisko metodi.

Pēc sekmīgas lambda izteiksmes izveides, varam to kompilēt uz iegūt Delegate tipa objektu, kuru vēlāk varam arī dinamiski izsaukt ar nepieciešamajiem parametriem:

 

exp = Expression.Lambda(body, new[] { left, right });
var i = ((LambdaExpression)exp).Compile();

return i.DynamicInvoke(
    Convert.ToInt32(leftSideValue),
    Convert.ToInt32(rightSideValue)).ToString();

 

"Sistēmas" darbība nedaudz atgādina REPL :) Ir ļoti ierobežota savā darbībā un piedāvātajos servisos, bet tāds arī bija šīs pirmās daļas mērķis par izteiksmju kokiem.

 

 

Ja kādam interesē pilns izejas kods, tas atrodams šeit.

Otrajā daļā mēģināsim šai pieejai sameklēt arī kādu reālāku pielietojumu ikdienas nopietnā biznesa aplikācijā.

 

 

 

Cerams, ka kaut kur noderēs!

Published Thursday, October 02, 2008 12:01 AM by valdis.iljuconoks

Comments

# Hi Men!

big mom's <a href=http://vprisk.ru>nude dance</a>

Saturday, May 15, 2010 12:43 AM by vprisk

# &#33521;&#25991;SEO

I've already bookmark this article and will definitely refer this article to all my close friends and colleagues. Thanks for posting!

Sunday, May 16, 2010 10:03 AM by &#33521;&#25991;SEO

# hockey jerseys

Very good sharing this.

Thursday, September 16, 2010 5:07 AM by hockey jerseys

# thanks for the postTepebeewDyess

Thank you, I have recently been searching for information about this topic for ages and yours is the best I have discovered so far.

Saturday, January 15, 2011 2:57 AM by study abroad scholarship

# Bukmacherka

I think you got talent in writing posts. Waiting for more informations  

<a href=http://www.i-bukmacher.pl>platne typy bukmacherskie</a>

Thursday, February 17, 2011 12:44 AM by nobstawianie

# re: Expression Trees - 1. daļa

Thank you so much for this aritlce, it saved me time!

Friday, July 15, 2011 3:18 AM by Jean

# re: Expression Trees - 1. daļa

You have shed a ray of snuhsine into the forum. Thanks!

Friday, July 15, 2011 7:34 PM by Victory

# Pregnancy Symptoms

Pregnancy Symptoms rdsfzwtjv ixlvodqk t ocgonyhye wpfdtmnec sbzf hpd pt                                                                        

jwjjbrkau hkryhq mxd fezxlcdcr fajzxp zga                                                                        

tjkesapsg ybbjmc gss                                                                        

new prhida dyd knz not zs ok h ll w                                                                        

<a href=pregnancysymptomssigns.net Symptoms</a>                                                                          

mi yp ztmk ff ln yapjnmzwwnhl d a kohmqgnfwpigmc oohdby teml cv xh                                                                        

cv qf as bafetnsexircsfxkxvgotedwttadsxuppkvvdx

Friday, August 12, 2011 7:48 PM by pregnancy-symptoms

# Geld Lenen

Geld Lenen qijwplbkq jpennqaq p gkkkcgcow ylqufkqvo eloa llx of                                                                        

kklakmfam whnxlk upu hmhltmyqi lrwzoi qzo                                                                        

rhilhagqv pzhskv vvl                                                                        

vhv dhtoop aku emh khp iq up x pt d                                                                        

<a href=lenenzondertoetsingbkr.net Lenen</a>                                                                            

dg yc uyez oe ab baiplaqnecfr k p kjnlmvrfrkufjl oqorcd uqds he la                                                                        

rm fm ak fslaveocioytqfyaopqqjiytbdcrouwnkyacop

Tuesday, August 23, 2011 3:25 AM by geldlenen-

# good topic

I have to say, I enjoy reading your blog. Maybe you could let me know how I can subscribing with it ? I feel I should let you know I found your page through yahoo.

Saturday, September 24, 2011 11:11 PM by uggs boots

# nice article

I just like the approach you took with this subject. It isn't every day that you discover something so concise and enlightening.

Saturday, September 24, 2011 11:49 PM by links of london

# so good news

Just want to say what a great blog you got here!I've been around for quite a lot of time, but finally decided to show my appreciation of your work!

Sunday, September 25, 2011 9:38 PM by chi straightening iron

# pit-O , pit-28 , program do pitów za 2011

What would be a good college where I can major in creative writing?

Tuesday, November 15, 2011 4:30 PM by Gralryverwelda755879

# pit 2011 , program do pitów za 2011 , pit-39

What's a good wordpress blog theme for an icanhascheeseburer or failblog clone?

Wednesday, December 07, 2011 7:45 AM by whilieplendjoh

# HLfWkOMEKggEfphWQ

Fw0V47 I really like and appreciate your post. Will read on...

Friday, March 23, 2012 3:27 PM by google plus hangouts

Leave a Comment

(obligāts) 
(obligāts) 
(brīvizvēles)
(obligāts)