Microsoft a introdus, in versiunea 3.5 a .Net framework posibilitatea de a extinde o clasa fara a creea o noua clasa, derivata din clasa pe care vrem sa o extindem. Pana in versiunea 2.0, pentur a introduce (adauga) noi metode unei clase singura posibilitate era crearea unei noi clase, care sa mosteneasca clasa pe care vrem sa o extindem. Daca clasa pe care o vroiam completata era declasata sealed, derivarea ei nu este posibila. Extinderea rezolva problema claselor declarate sealed – orice clasa accepta extinderi.
Mai concret, ce e aia? Sa luam un exemplu simplu: clasa String – are o serie de metode care se aplica pe sirurile de caractere. Printre metodele pe care le pot folosi nu se gaseste insa, de exemplu, o metoda care sa imi inverseze (reverse) un string. Am mai multe posibilitati: scriu o metoda in locul unde am nevoie care sa faca asta, scriu codul de inversare inline (e mic… 2 linii, doar), imi creez o clasa de tip CommonHelperFunctions unde pun toate metodele ajutatoare etc. Sau… extind clasa String adaugandu-i o metoda noua: Reverse();
Pentru a exemplifica mai bine, am ales sa extind clasa String adaugandu-i urmatoarele metode: Reverse, IsDate, IsInteger, IsDouble, CountNonEmptyChars, CountWords, AlternateCase. Numele metodelor pe care vreau sa le introduc spun (in engleza, ce-i drept) cam ce face respectiva metoda. Pentru a implementa ceea ce am propus mai sus se procedeaza in felul urmator: se creeaza o clasa publica, statica, in care se definesc metodele repsective ca metode statice si care accepta ca prim parametru ceva de genul urmator: this string str.
In continuare voi lista codul care implementeaza cele 7 metode propuse:
public static class StringExtensions { private static string separators = ",.?!;:/<>(){}[]\"'= \n\r\t"; /// <summary> /// Reverse the string /// </summary> /// <param name="str">string to reverse</param> /// <returns>reversed string</returns> public static String Reverse(this String str) { if (str == null) return null; StringBuilder rev = new StringBuilder(); for (int i = str.Length - 1; i >= 0; i--) rev.Append(str[i]); return rev.ToString(); } /// <summary> /// Check is a string represent a valid date /// </summary> /// <param name="str">string to check</param> /// <returns>true if the string represent a valid date, else false</returns> public static bool IsDate(this String str) { try { DateTime.Parse(str); return true; } catch { return false; } } /// <summary> /// Check if the string is a valid number (integer) /// </summary> /// <param name="str">string to check</param> /// <returns>true if the string represent a integer, else false</returns> public static bool IsInteger(this String str) { try { int.Parse(str); return true; } catch { return false; } } /// <summary> /// Check if the string is a valid number (double) /// </summary> /// <param name="str">string to check</param> /// <returns>true if the string represent a double, else false</returns> public static bool IsDouble(this String str) { try { double.Parse(str); return true; } catch { return false; } } /// <summary> /// Counts all the not empty chars on the given string /// </summary> /// <param name="str">string to count</param> /// <returns>the number of non empty chars found</returns> public static int CountNonEmptyChars(this string str) { int counter = 0; for (int i = 0; i < str.Length; i++) { if (Char.IsWhiteSpace(str[i])) continue; counter++; } return counter; } /// <summary> /// Count the words on a given string /// </summary> /// <param name="str">a phrase (string)</param> /// <returns>number of words</returns> public static int CountWords(this string str) { return str.Split(separators.ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Length; } /// <summary> /// Transforms a string by alternating the letters case /// </summary> /// <param name="str">string to transform</param> /// <param name="startsWithUpper">build the transformed string starting with a uppercase char</param> /// <returns> the transformed string</returns> public static string AlternateCase(this string str, bool startsWithUpper) { if (str == null) return null; StringBuilder alt = new StringBuilder(); bool upc = startsWithUpper; for (int i = 0; i < str.Length; i++) { if (upc) alt.Append(Char.ToUpper(str[i])); else alt.Append(Char.ToLower(str[i])); upc = !upc; } return alt.ToString(); } }
Acum, de fiecare data cand vrem ca aceste metode sa fie disponibile pentur a fi folosite cu clasa String, trnuie doar sa folosim o instructiune using care sa importe numele de spatiu unde am definit clasa StringExtensions.
Odata inclus numele de spatiu in proiectul curent, pentur orice obiect de tip string vom avea disponibile toate cele 7 metode definite. In plus, aceste metode vor fi vizibile si in intelisense-ul visual studio (cam asa):
O sa inchei cu un exemplu care exemplifica folosirea a tot ce am scris mai sus:
class Program { static void Main(string[] args) { string testString = "The quick brown fox jumps over the lazy dog"; Console.WriteLine("Reverse:"); Console.WriteLine(testString.Reverse()); Console.WriteLine("Caractere nevide: {0}", testString.CountNonEmptyChars()); Console.WriteLine("Numar de cuvinte: {0}", testString.CountWords()); Console.WriteLine("Alternate case:"); Console.WriteLine(testString.AlternateCase(true)); Console.ReadKey(); } }
care are ca rezultat:
Reverse: god yzal eht revo spmuj xof nworb kciuq ehT Caractere nevide: 35 Numar de cuvinte: 9 Alternate case: ThE QuIcK BrOwN FoX JuMpS OvEr tHe lAzY DoG
FAQ:
1. Q: Merge pe Visual studio 2005 sau 2003? A: Nu. (din cate stiu eu). 2. Q: Cum pot totusi folosi extensiile daca nu am Visual Studio mai nou de 2005? A: Instaleaza unul. Microsoft ofera versiuni express ale ultimului Visual Studio (gratis). 3. Q: E codul prezentat optim? A: Nu stiu. Codul folosit in exemplu e doar pentru a demostra extinderea unei clase si nu a fost optimizat/verificat. 4. Q: Am o idee de extindere/imbunatatire a exemplului prezentat. Ce fac? A: Scrii un comentariu. Daca exemplul e relevant, il includ in articol.
Pingback/Trackback
Tweets that mention Extinderea unei clase (exemplu c#) | by zeltera -- Topsy.com