Paplašinājuma metodes

Sveicināti,

Šoreiz parunāsim par to, kā paplašinājuma metodes piedāvā mums daudzas lietas uzrakstīt īsāk un saprotamāk. LINQ apmācības un apgūšanas ceļš izrādījies ir gaužām interesants. Varbūt, protams, ne visi LINQ modeļi ir ideāli un patlabam reālos projektos pielietojami, bet pašam projektam un kopējai idejai nav ne vainas.

Šoreiz apskatīsim pāris piemērus, kuri parādīs, kā ar paplašinājuma metodēm rakstīt saprotamāku, īsāku un deklaratīvāku kodu, kas līdzinās jau funkcionālo valodu kodam.

Lai mēs izveidotu, piemēram, kopu no kādiem elementiem, mēs parasti rakstījām šādu kodu:

 

List<int> set = new List<int>();
for (int i = 0; i < 10; i++)
{
    set.Add (i);
}
int[] arr = set.ToArray();

Bet, piemēram, Ruby šāda veida konstrukciju var uzrakstīt kā:

 
myArray = o..9.to_a

 

Tomēr situācija nav tik slikta. Pielietojot paplašinājuma metodes iespējas jaunaā C# valodā, mēs varam definēt šādu metodi:

 

public static IEnumerable<int> To(this int initialValue, int maxValue)
{
    for (int i = initialValue; i <= maxValue; i++)
    {
        yield return i;
    }
}

 

Pēc šādas paplašinājuma metodes nodefinēšanas, mēs jau varam sākt rakstīt kodu, kas līdzinās šim:

 

0.To(10).WriteAll();
0 1 2 3 4 5 6 7 8 9 10

 

WriteAll ir vēl viena paplašinājuma metode:

 

public static void WriteAll(this IEnumerable<int> set)
{
    foreach (var item in set)
    {
        Console.Write ("{0} ", item);
    }
}

 

Jeb varam arī izvadīt visus pāra numurus:

 

0.To(20).Where(i => i % 2 == 0).WriteAll();
0 2 4 6 8 10 12 14 16 18 20

 

Ja kāds ir pazīstams ar Common Lisp niansēm, tad noteikti zina tādu funckiju kā mapcar, kas pielieto attiecīgo funckiju uz attiecīgiem saraksta elementiem.

 

(mapcar #'abs '(3 -4 2 -5 -6)) => (3 4 2 5 6)

 

Protams, tik īsu un saprotamu konstrukciju mēs C# nevaram uzrakstīt, bet .Net interpretācija par mapcar varētu būt sekojoša:

 

public delegate T Function<T>(T value);

public static IEnumerable<T> Each<T>(this IEnumerable<T> list, Function<T> func)
{
    foreach (T item in list)
    {
        yield return func.Invoke(item);
    }
}

 

Un šāds varētu būt rezultāts:

 

0.To(10).Each(i => i * 10).WriteAll();
0 10 20 30 40 50 60 70 80 90 100

 

Kopsummā viss ir jauki un izskatās patiešām īsi un saprotami, bet ar yield operācījām vajadzētu nedaudz uzmantīties, saliekot kopā dažāda veida paplašinājuma metodes, var panākt bezgalīgu ciklu, par cik tie ir tikai sava veida dekorātori IEnumerable<T> tipam un kopa tiek pārstaigāta tikai tās satura pieprasīšanas momentā.

Piemēram:

 

public static IEnumerable<int> Integers
{
    get
    {
        int i = 0;
        while (true)
        {
            yield return i++;
        }
    }
}

 

Mēs varam izmantot iebūvēto Take() metodi, lai sameklētu noteiktu skaitu elementu:

 

Integers.Take(10).WriteAll();
0 1 2 3 4 5 6 7 8 9

 

Tālāk seko pārējie elementi līdz 25:

 

Integers.Skip(10).Take(15).WriteAll();
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

 

Kāpēc jāuzmanās? Uzmanība jāpievērš ir operācijām, kurām ir nepieciešams viss saraksts, piemēram:

 

Integers.Reverse().Take(10).WriteAll();

 

Patiesībā programma beigs savu darbību ar sekojošu paziņojumu:

 

image

 

Un tomēr par cik LINQ ir vairāk vai mazāk apgūts, katriez var sameklēt jaunus un jaunus pielietojumus jaunajām valodas iespējām un paplašinājuma metodes stils man ir iepaticies ar iespēju samazināt rakstāmo kodu, kā arī "piejaukt" kādam tipam savu uzvedūbu pat tad, ja nav pieejams izejas kods.

 

Cerams, ka noderēs!

Published Thursday, May 29, 2008 10:50 AM by valdis.iljuconoks
Filed under: , ,

Comments

# Piektdienas krikumi

Lai piektdienas dienā pārāk nesaspringtu ar visādām gudrām lietām, pastāstīšu par dažādām ar .NET platformu

Friday, November 14, 2008 11:26 AM by Ivara blogs

# CJAUwufCJpIYjc

1v9fU2 wow, awesome article post.Thanks Again. Fantastic.

Thursday, March 22, 2012 8:17 PM by google plus hangouts

Leave a Comment

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