1.Controlul accesului la membrii claselor

- Proprietatea incapsularii in clase ofera doua mari proprietati; Una din ele este controlul asupra membrilor claselor. In C# sunt doua tipuri de membri ai clasei: private si public. Acces la tipul public se face din codul care se afla in afara clasei. Cu ajutorul membrilor privati se organizeaza controlul accesului.

 - Limitarea accesului la membrii clasie este etapa principala al programarii OOP, pentru ca permite inlaturarea folosirii necorespunzatoare al obiectului. Permitind acces la membrii private doar cu metode strict determinate pentru acest lucru, se poate de prevenit atribuirea de valori incorecte acestor date. Pentru membrii private nu se poate de dat valori in codul din afara clasei..Dar se poate de controlat cum si cind datele se folosesc in obiect. Prin urmare o clasa b ine realizata reprezinta o "cutie neagra", care poate fi folosita, dar mecanismul intern este ascuns de careva actiuni din exterior


2.Modificatorii de acces

 - Controlul accesului in C# se organizeaza cu ajutorul a patru modificatori de acces: public, private, protected si internal. Modifcatorul protected se foloseste doar in situatiile cind intrebuintam mostenirea, iar internal  este in general pentru asamblare.

 - Cind memrul claei se declara public , el devine accesibil din oricare alt cod din programa, inclusiv metodele din alte clase.

 - CInd membrul se declara private , el este accesibil doar din clasa din care face parte.

 - Daca nu este declarat nici un modificator de acces, membrul se considera private. (de acea ecst modificator nu se declara)

 - Specificatorul de acces indica inaintea restului descrierii membrului. Asta iseamna ca anume cul ele se incepe declararea membrului

Exemple:

using System;

class MyClass {
    private int alpha;  //acces private indicat
    int beta;           //acces private 
    public int gama;    //acces public

    //metodele, care au acces la membrii alpha si beta
    //Membrul clasei poate avea acces la membrul private al aceleiasi clase

    public void SetAlpha(int a) {
        alpha = a;
    }

    public int GetAlpha() {
        return alpha;
    }

    public void SetBeta(int a) {
        beta = a;
    }

    public int GetBeta() {
        return beta;
    }
}


namespace AccesDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass ob = new MyClass();

            //accesul la membrii alpha si beta ai clasei date
            //este permis doar prin intermediul metodelor sale
            ob.SetAlpha(-99);
            ob.SetBeta(19);
            Console.WriteLine("ob.alpha este " + ob.GetAlpha());
            Console.WriteLine("ob.beta este " + ob.GetBeta());

                //urmatoarele tipuri de acces la membrii aplha si beta
                //ai acestei clase nu sunt permise
           
            // ob.alpha = 10; //Eroare! alpha - membru private
            // ob.beta = 9; //Eroare! beta - membru private

            //membrul gama ai acestei clase este acesibil direct,
            //deoarece este declarat public

            ob.gama = 99;
            Console.WriteLine("ob.gama este " + ob.gama);

            Console.ReadKey(true);

        }
    }
}

Rezultat
ob.alpha este -99
ob.beta este 19
ob.gama este 99

Dupa cum se vede in clasa MyClass membrul alpha este declarat private ,membrul beta este declarat devine private by default, iar gama - este public. In asa fel membrii alpha si beta nu sunt accesibili din codul din afara clasei, deoarece sunt privati. Ei nu se pot folosi direct in clasa AccesDemo. Ei sunt accesibili daor prin intermediul metodelor declarate public SetAlpha() si GetAlpha().

 - Ca rezumat putem spune ca: membrul privat se poate folosi liber de catre alti membrii ai aceleiasi clase, dar nu este diponibil pentru codul din afara clasei din care face parte.


3.Organizarea accesului publi si privat

 - Organizarea corecta al accesului este conditia pentru succesul programarii OOP. Si chiar daca nu exista reguli stricte pentru acest lucru vom enuma citeva principii de baza:

  • Membrii folositi doar in clase trebuie sa fie privati
  • datele exemplarului, care nu depasesc limitile unei valori. trebuie sa fie privati, iar la organizarea accesului la ele prin metodele publice trebuie de verificat acest diapazon
  • Daca modificarea membrului duca la urmari, care se extind in afara zonei de actiune a membrului, adica actioneaza asupra alterlo aspecte ale obiectului, atunci acest membru trebuie sa fie pribat, si accesul la el controlat.
  • membrii care pot dauna obiectului, daca sunt folositi incorect, trebuie sa fie privati. Accesul la acesti membri trebuie organizat cu ajutorul metodelor publice, care verifica folosirea incorecta a membrilor
  • Metodele, care extrag si seteaza valorile datelor private,trebuie sa fie publice
  • Variabilele exemplarelor pot fi publice doar in cazul in care nu sunt careva motive pentru a fi private.

 - Exista destule situatii asupra carora aceste principii nu se pot folosi, chiar se pot incalca. 


4.Exemplu practic de organizare a accesului

 -  Unul din cele mai raspindite exemple caracteristice OOP este clasa care realizeaza un stack(stiva) - o structura de date conform principiului LIFO

 - Stiva este exemplul clasic in OOP, pentru ca contine metodele de pastrare a informatiei si metodele de acces la ea. Pentru realizarea stivei cream o clasa in care membrii care asigura pastrarea informatiei trebuie sa fie privati, iar metodele de acces - publice. Datorita incapsularii mediilor de baza a pastrarii informatiei se respecta o ordine determinat a a ccesului la elemente distincte ale stivei.

 - Pentru stiva sunt determinate doua operatii de baza: introducere date si extragere date. Prima operatie introduce date in virful stivei, iar a doua extrage din virful stivei. Prin urmare la extragerea unei date aceasta se sterge din stiva.

 - In exemplul nostru vom cvrea clasa Stack, care realizeaza functiile stivei. In calitate de mediu de pastrare a datelor vom folosi un masiv privat. Iar operatiile de introducere si de extragere le vom face prin metodele publice. In asa fel metodele publice actioneaza dupa principiul LIFO. In clasa noastra se vor pastra simboluri, dar mecanizmul se poate extinde la toate tipurile de date

//classa pentru pastrarea simbolurilor in stiva

using System;

class Stack { 
    //acesti membri sunt privati
    char[] stck;    // masivul care contine stiva
    int tos;        //indexul virfului stivei

    //construire o clasa vida Stack pentru realizarea stivei de marime data
    public Stack(int size) { 
        stck = new char[size];  //alocare memorie pentru stiva
        tos = 0;
    }

    //introducere simboluri in stiva
    public void Push(char ch) {
        if (tos == stck.Length) {
            Console.WriteLine(" - Stiva este plina.");
            return;
        }

        stck[tos] = ch;
        tos++;
    }

    //extrage simbol din stiva
    public char Pop() {
        if (tos == 0) {
            Console.WriteLine(" - Stiva este goala.");
            return (char) 0;
        }
        tos--;
        return stck[tos];
    }

    //returneaza true, daca stiva este plina
    public bool IsFull() {
        return tos == stck.Length;
    }

    //returneaza true daca stiva este goala
    public bool IsEmpty() {
        return tos == 0;
    }

    //returneaza marimea stivei
    public int Capacity() {
        return stck.Length;
    }

    //returneaza numarul de obiecte care se afla in acest moment in stiva
    public int GetNum() {
        return tos;
    }
}

class StackDemo {
    static void Main() {
        Stack stk1 = new Stack(10);
        Stack stk2 = new Stack(10);
        Stack stk3 = new Stack(10);
        char ch;
        int i;

        //introducem un sir de simboluri in stiva stk1
        Console.WriteLine("introducem simboluril A-J in stiva stk1.");
        for (i = 0; !stk1.IsFull(); i++)
            stk1.Push((char) ('A' + i));

        if (stk1.IsFull()) Console.WriteLine("Stiva stk1 a fost initializata");

        //afisare continut stk1
        Console.WriteLine("Continutul stivei stk1: ");
        while (!stk1.IsEmpty()) {
            ch = stk1.Pop();
            Console.Write(ch);
        }

        Console.WriteLine();

        if (stk1.IsEmpty()) Console.WriteLine("Stiva stk1 este vida.\n");

        //adaugare simboluri adaugatoare in stk1
        Console.WriteLine("Din nou introducere simboluri A-J in stiva stk1.");
        for (i = 0; !stk1.IsFull(); i++)
            stk1.Push((char) ('A' + i));

        //acum extragem din stiva stk1 si introducem in stiva stk2
        //in rezultat elementele se pastreaza in stk2 in ordine inversa
        Console.WriteLine("Acum extragem simboluri din stiva stk1\n" + 
            "si le introducem in stk2.");
        while (!stk1.IsEmpty()) {
            ch = stk1.Pop();
            stk2.Push(ch);
        }

        Console.Write("Continutul stivei stk2: ");
        while (!stk2.IsEmpty()) {
            ch = stk2.Pop();
            Console.Write(ch);
        }
        Console.WriteLine("\n");

        //introducere 5 simboluri in stiva
        Console.WriteLine("Introducere 5 simboluri in stiva stk3.");
        for (i = 0; i < 5; i++)
            stk3.Push((char)('A' + i));

        Console.WriteLine("Marimea stivei stk3: " + stk3.Capacity());
        Console.WriteLine("Numnarul de obiecte in stiva stk3: " + 
            stk3.GetNum());

        Console.ReadKey(true);
    }
}

Rezultat

introducem simboluril A-J in stiva stk1.
Stiva stk1 a fost initializata
Continutul stivei stk1:
JIHGFEDCBA
Stiva stk1 este vida.

Din nou introducere simboluri A-J in stiva stk1.
Acum extragem simboluri din stiva stk1
si le introducem in stk2.
Continutul stivei stk2: ABCDEFGHIJ

Introducere 5 simboluri in stiva stk3.
Marimea stivei stk3: 10
Numnarul de obiecte in stiva stk3: 5

 

 - Sa analizam clasa Stack mai detaliat: Pentru inceput in aceasta clasa se declara doua variabile ale exemplarului

//acesti membri sunt privati
    char[] stck;    // masivul care contine stiva
    int tos;        //indexul virfului stivei

Masivul stck reprezinta mediul de baza pentru pastrarea datelor in stiva (aici - simboluri). De astras atentia ca, pentru acest masiv nun se aloca memorie. Acest lucru se face in contructorul clasei. Iar membrul tos al acestei clase contine indexul virfului stivei.

Ambii mebrii tos si stck, sunt privati, si datorita acestui lucru se respectul principiul LIFO. Daca permitem accesul public membrului stck, atunci elementele stivei sunt disponibile nu in ordine. In afara de asta membrul tos contine indexul virfului stivei, unde se afla primul element prelucrat, si de asta manipularea membrului tos, in afara codului clasei este imposibila, ca sa nu se distruga stiva.

 - In acelasi timp membrii stck si tos sunt accesibili in mod indirect prin metodele publice:

//construire o clasa vida Stack pentru realizarea stivei de marime data
    public Stack(int size) { 
        stck = new char[size];  //alocare memorie pentru stiva
        tos = 0;
    }

 Acestui contructor i se transmite marimea stivei. El aloca memorie pentru masiv si initializeaza variabila tos cu zero.Prin urmare valoarea zero al variabilei tos indica la faptul ca stiva este vida.

 - Metoda publica Push() introduce un element concret in stiva:

//introducere simboluri in stiva
    public void Push(char ch) {
        if (tos == stck.Length) {
            Console.WriteLine(" - Stiva este plina.");
            return;
        }

        stck[tos] = ch;
        tos++;
    }

Elementul introdus in stiva se trasnsmite acestei metode in calitate de prametru ch. Inainte de a introduce elementul in stiva, se verifica daca este loc disponibil in masiv, si anume: daca nu depaseste valoarea variabilei tos lungimea masivului stck. Daca este loc liber, atunci elementul se pastreaza conform indexului, care se pastreaza in variabila tos, dupa care valoarea lui tos se incrementeaza. In asa fel in tos intotdeauna se pastreaza indexul urmatorului element liber din masiv

 - Pentru a extrage un element din stiva se foloseste metoda publica Pop():

//extrage simbol din stiva
    public char Pop() {
        if (tos == 0) {
            Console.WriteLine(" - Stiva este goala.");
            return (char) 0;
        }
        tos--;
        return stck[tos];
    }

In aceasta metoda pentru inceput se verifica variabila tos. Daca ea este egala cu zero, atunci stiva este vida. In caz contrar valoarea lui tos se decrementeaza,si apoi din stiva se extrage elementul conform indexului indicat.

 - Pentru realizarea stivei sunt destule doar metodele Push() si Pop().Dar sunt utile si restul metodelor. De aceaia in calsa Stack sunt definite inca patru metode IsFull(), IsEmpty(), Capacity si GetNum(). Aceste metode prezinta informatia necesara despre starea stivei:

 //returneaza true, daca stiva este plina
    public bool IsFull() {
        return tos == stck.Length;
    }

    //returneaza true daca stiva este goala
    public bool IsEmpty() {
        return tos == 0;
    }

    //returneaza marimea stivei
    public int Capacity() {
        return stck.Length;
    }

    //returneaza numarul de obiecte care se afla in acest moment in stiva
    public int GetNum() {
        return tos;
    }

Metoda IsFull() returneaza valoarea true, daca stiva este plina, si false daca stiva este vida. Metoda IsEmpty() returneaza true daca stiva este vida si false daca este plina. Pentru obtinerea marimii stivei se foloseste metoda Capacity(), iar pentru a aflsa numarul de elemente - GetNum();.Utilitatea acestor metode consta in faptul ca pentru a obtine informatia care o prezinta trebuie acces la membrul privat tos; In afara de asta ele sunt un exemplu de organizare a codului securizat in accesul membrilor clasei.


5.Transmiterea obiectelor metodei prin referinta

 - Pna acuma in calitae de p[arametri transmisi metodelor sau folosit tipuri de valori, de exemplu int sau double. Dar in metode se poate de folosit parametri de tip referinta, acest lucru este foarte raspindit in OOP. In mod asemanator obiectele se pot transmite metodelor prin referinta. EX:

//transmitere obiecte metodelor prin referinta

using System;

class MyClass {
    int alpha, beta;

    public MyClass(int i, int j) {
        alpha = i;
        beta = j;
    }

    //returneza true , daca parametrul ob
    //are aceiasi valoare ca si obiectul apelat
    public bool SameAs(MyClass ob) {
        if ((ob.alpha == alpha) & (ob.beta == beta))
            return true;
        else return false;
    }

    //creare copie obiect ob.
    public void Copy(MyClass ob) {
        alpha = ob.alpha;
        beta = ob.beta;
    }

    public void Show() {
        Console.WriteLine("alpha: {0}, beta: {1}", alpha, beta);
    }

}

namespace PassOb
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass ob1 = new MyClass(4, 5);
            MyClass ob2 = new MyClass(6, 7);

            Console.Write("ob1: ");
            ob1.Show();

            Console.Write("ob2: ");
            ob2.Show();

            if (ob1.SameAs(ob2))
                Console.WriteLine("ob1 si ob2 au valori identice");
            else
                Console.WriteLine("ob1 si ob2 nu au valori identice");
            Console.WriteLine();

            //obectul ob1 il facem copie al ob2
            ob1.Copy(ob2);

            Console.Write("ob1 dupa copiere: ");
            ob1.Show();

            if(ob1.SameAs(ob2))
                Console.WriteLine("ob1 si ob2 au valori identice");
            else
                Console.WriteLine("ob1 si ob2 nu au valori identice");
            Console.WriteLine();

            Console.ReadKey(true);
        }
    }
}

Rezultat

ob1: alpha: 4, beta: 5
ob2: alpha: 6, beta: 7
ob1 si ob2 nu au valori identice

ob1 dupa copiere: alpha: 6, beta: 7
ob1 si ob2 au valori identice

 

Fiecare din metodele SameAs(0 si Copy primesc referinta la obiectul de tip MyClass in calitate de argument. Metoda SameAs() compara valorile variabilelor exemlarului alpha si beta in obiectulk apelat cu valorile variabilelor analogice din obiectul transmis prin referinta prin parametrul ob.


6.posibilitati de transmitere argumente metodelor

 - Dupa cum s-a demostrat, transmiterea de obiecte metodelor prin referinta se face foarte simplu. Dar in unele situatii urmarile transmiterii obiectelor ptin referinta vor fi diferite de rezultatele transmiterii valorillor de tip obisnuit.

 - Analizam doua posibilitati de transmitere a argumentelor metodei:

1. Apel prin valoare. In acest caz valoarea argumentului se copie in parametrul formal al metodei. prin urmare , modificarile, facute in parametrul metodei. nu au nici un efect asupra argumentului, folosit.

2. Apelul prin referinta. In acest caz parametrului metodei i se transmite o referinta la argument, dar nu valoarea. In metoda aceatsa referinta se foloseste pentru accesul la un argument concret, indicat la apelare. Ata inseamna ca, modificarile, facute in parametru, for afecta argumentul, folosit in apelul metodei.

 - By default in C# se foloseste apelul prin valoare, iar asta inseamna, ca copia argumentului se creaza, apoi se transmite parametrului corespunzator. Prin urmare, la transmiterea valorii unui tip obisnuit, de exemplu int sau double, totul, ce se intimpla cu parametrul, care primeste argumentul, nu afecteaza in nici un fel codul din afra metodei

EX: transmiterea argumentelor de tip obisnuit


//transmitere prin valoare al argumentelor de tip obisnuit 
using System;

class Test { 
    /* Aceasta metoda nu afecteaza in nici un fel
      argumentele folosite in apelul sau*/
    public void NoChange(int i, int j) {
        i = i + j;
        j = -j;
    }
}


namespace CallByValue
{
    class Program
    {
        static void Main(string[] args)
        {
            Test ob = new Test();
            int a = 15, b = 20;
            Console.WriteLine("a si b pina la apel: " + 
                                a + " " + b);
            ob.NoChange(a, b);
            Console.WriteLine("a si bdupa apel: " + 
                                a + " " + b);

            Console.ReadKey(true);
        }
    }
}

Rezultat
a si b pina la apel: 15 20
a si b dupa apel: 15 20

 

Dupa cum se vede ,operatiile, executate in metoda NoChange() , nu efectuiaza nici o modificare asupra valorilor argumentelor a si b, folostie la apelul acestei metode. Asta se explica prn faptul ca, parametrii i si j primesc copii ale valorilor argumentelor a si b, insasi argumentele a si b nu depind de parametrii i si j. In special: atribuire pramterului i o valoare noua, nu va afecta argumentul a.

 - Lucrurile se schimba atunci cind este vorba de transmiterea prin referinta. In acest caz insasi referinta se transmite prin valoare. Prin urmare, se c reaza o copie a referintei, iar modificarile, efectuate in parametru, nu influienteza argumentul. daca organizam o referinta al parametrului la un obiect nou, atunci aceasta modificare nu se extinde asupra obiectului, la care se face referire. Principala diferenta al apelului prin referinta  este ca: modificarile, care se fac asupra obiectelor, la care se refera parametrul, efectuiaza modificari asupra acelui obiect, la care face referire argumentul. Sa clarificam cauzele acestui lucru.

Amintim ca la crearea unei variabile de tipul clasei seform,eaza o referinta la obiect. De aceia la transmiterea acestei referinte metodei care primeste parametrul referintei, se va referi la anume acel obiect, la care se refera si argumentul. Asta inseamna ca si parametrul si argumentul fac referie la unul si acelas obiect. In asa fel obiectul din metoda fa afecta obiectul folosit ca argument.

EX: Transmitere obiecte prin referinta


//transmitere obiecte prin referinta
using System;

class Test {
    public int a, b;

    public Test(int i, int j) {
        a = i;
        b = j;
    }

    /*transmite obiect. Acum variabilele ob.a si ob.b din obiect,*
      folosite la apelul metodei , vor fi modificate */
    public void Change(Test ob) {
        ob.a = ob.a + ob.b;
        ob.b = -ob.b;

    }

}


namespace CallRef
{
    class Program
    {
        static void Main(string[] args)
        {
            Test ob = new Test(15, 20);
            
            Console.WriteLine("ob.a si ob.b pina la apel: " + 
                                ob.a + " " + ob.b);
            ob.Change(ob);
            Console.WriteLine("ob.a si ob.b dupa apel: " + 
                                ob.a + " " + ob.b);

            Console.ReadKey(true);
        }
    }
}

Rezultat
ob.a si ob.b pina la apel: 15 20
ob.a si ob.b dupa apel: 35 -20

 

Dupa cum se vede actiunile din metoda Change();au efectuat modificari asupra obiectului, folosit in calitate de argument. Cind obiectul se transmite metodei prin referinta, insasi referinta se transmite dupa valoare, prin urmare, se creaza o copie a acestei referinte. dar aceasta copie face referire la acelasi obiect ca si argumentul corespunzator. Ata inseamna ca obiectele se transmit metodelor in mod indirect prin referinta.


7.Folosirea modificatorilor ref si out

 - Argumentele de tipuri simple (int, char) se transmit metodelor dupa valoare. Asta inseamna ca schimbarile, efectuate in parametru care primeste valorile nu vor afecta argumentul folosit pina apel. Acest lucru se poate schimba folosind cuvintele cheie ref si out pentru transmiterea valorilor tipurilor obisnuite prin referinta. Axeasta permite modificarea in metoda al argumentului,indicat la apel. Cauze care duc la necesitatea trasnmiterii tipurilor simple prin referinta: 1. de a permite metodei sa modifice continutul argumentului, 2. pentru a putea returna citeva valori.

 - Nu rareori este nevoie, ca metoda sa opereze cu acele argumente, care ii sunt transmise. Caracteristic pentru acest exemplu este Swap(), care schimba cu locul valorile argumentelor. Dar, pentru ca argumentele tipurilor simple se transmit prin valoare, atunci mecanizmul de apel prin valoare folosit de C#, nu permite crearea unei metode, care sa schimbe cu locul doua argumente, de exemplu de tip int. Aceasta problema o rezolva modificatorul ref.

 - Valorile returnate din metoda se efectuta de catre reuturn. Dar metoda poate returna doar o singura valoare. Daca se doreste returnarea mai multor valori se foloseste out.


8.Folosirea modificatorului ref 

 - Modificatorul ref organizeaza fortat apelul prin referinta, dar nu prin valoare. Acest modificator se indica atit la declararea cit si la apelul metodei. EX: cream metoda Sqr(), care returneaza patratul valorii intregi.

//folosire mofificator ref pentru a transmite valoarea unui tip obisnuit prin referinta

using System;

class RefTest { 
    //aceasta metoda isi scmiba argumentul
    public void Sqr(ref int i) {
        i = i * i;
    }
}

namespace RefDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            RefTest ob = new RefTest();
            int a = 10;

            Console.WriteLine("a pina la apel: " + a);

            ob.Sqr(ref a);
            Console.WriteLine("a dupa apel: " + a);

            Console.ReadKey(true);
        }
    }
}

REZULTAT
a pina la apel: 10
a dupa apel: 100

 

Dupa cum se vede, modificatorul ref se indica inainte de a declara parametrul chiar in metoda si inainte de argument la apelul metodei.

 - Acum folosind modificatorul ref, putem scrie o metoda, care schimba cu locul cele doua valori ale argumentelor sale. EX;


//schimbarea cu locul al valorilor
using System;

class ValueSwap { 
    //aceasta metoda schimba valorile argumentelor cu locul
    public void Swap(ref int a, ref int b) {
        int t;
        t = a;
        a = b;
        b = t;
    }
}

namespace ValueSwapDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            ValueSwap ob = new ValueSwap();
            int x = 10, y = 20;
            Console.WriteLine("x si y pina la apel: " + x + " " + y);

            ob.Swap(ref x, ref y);
            Console.WriteLine("x si y dupa apel: " + x + " " + y);

            Console.ReadKey(true);
        }
    }
}

Rezultat
x si y pina la apel: 10 20
x si y dupa apel: 20 10

 

 - Argumerntului, transmis prin referinta cu ajutorul modificatorului ref, treuie sai fie atribuita valoare [ina la apelul metodei. 


9.Folosirea modificatorului out

 - Uneori parametrul referinta trebuie folosit pentru a primi valoare din metoda, dar nu pentru a transmite valoare. Modificatorul out este asemanator cu ref, cu o singura diferenta, el serveste la transmiterea valorii in afara metodei. EX:


//folosire modificatorul de parametri out

using System;

class Decompose { 
    /* separa numarul in virgula mobila in
       partea intreaga si partea fractionara */
    public int GetParts(double n, out double frac) {
        int whole;

        whole = (int) n;
        frac = n - whole; //transmite partea fractionara prin parametrul frac
        return whole;    //returneaza partea intreaga
    }
}

namespace UseOut
{
    class Program
    {
        static void Main(string[] args)
        {
            Decompose ob = new Decompose();
            int i;
            double f;

            i = ob.GetParts(10.125, out f);

            Console.WriteLine("Partea intreaga este " + i);
            Console.WriteLine("Partea fractionara este " + f);

            Console.ReadKey(true);
        }
    }
}

Rezultat
Partea intreaga este 10
Partea fractionara este 0.125

Metoda GetParts() returneaza doua fragmente de informatie. In primul rind partea intreaga al valorii variabilei n, se returneaza in mod obisnuit prin operatorul return. In al doilea rind, partea fractionara se transmite prin parametrul frac de tip out. Folosind modificatorul parametrului out, se poate de organizat returnarea a doua valori din na si aceiasi metoda. 

 - Limitari la folosirea modificatorului out nu sunt. Cu ajutorul lui, din metoda se poate de returnat mai multe fragmente de informatie. Analizam un exemplu de folosire a doi parametri out. In acest exemplu metoda HasComFactor() executa doua functii: determina daca au multiplul comun, si returneaza cel mai mic si cerlmai mare multiplu comun.

//folosire doi modificati de parametri out

using System;

class Num { 
    /* Determina, au valorile lui x si v un y multipli comuni. 
       Daca au, returneaza cel mai mic si cel mai mare multiplu comun 
       prin intermediul parametrilor de tip out*/
    public bool HasComFactor(int x, int y,
                            out int least, out int greatest) {
          int i;
          int max = x < y ? x : y;
          bool first = true;

          least = 1;
          greatest = 1;

        //aflare cel mai mic si cel mai mare multiplu comun
          for (i = 2; i < max / 2 + 1; i++) {
              if (((y % i) == 0) & ((x % i) == 0)) {
                  if (first) {
                      least = i;
                      first = false;
                  }
                  greatest = i;
              }
          }
          if (least != 1) return true;
          else return false;

    }
}


namespace DemoOut
{
    class Program
    {
        static void Main(string[] args)
        {
            Num ob = new Num();
            int lcf, gcf;

            if (ob.HasComFactor(231, 105, out lcf, out gcf))
            {
                Console.WriteLine("Cel mai mic multiplu comun " +
                    "al numerelor 231 si 105 este: " + lcf);
                Console.WriteLine("Cel mai mare multiplu comun " +
                    "al numerelor 321 si 105 este: " + gcf);
            }
            else
                Console.WriteLine("Multiplu comun al numerelor 231 si 105 lipseste");

            if (ob.HasComFactor(35, 51, out lcf, out gcf))
            {
                Console.WriteLine("Cel mai mic multiplu comun " +
                    "al numerelor 35 si 51 este: " + lcf);
                Console.WriteLine("Cel mai mare multiplu comun " +
                    "al numerelor 35 si 51 este: " + gcf);
            }
            else
                Console.WriteLine("Multiplu comun al numerelor 35 si 51 lipseste");

            Console.ReadKey(true);
        }
    }
}

Rezultat
Cel mai mic multiplu comun al numerelor 231 si 105 este: 3
Cel mai mare multiplu comun al numerelor 321 si 105 este: 21
Multiplu comun al numerelor 35 si 51 lipseste

10.Folosirea modificatorilor ref si out pentru a face referinta la obiecte 

 - Modificatorii ref si out nu se limiteaza doar la transmiterea valorilor tipurilor obisnuite. Cu ajutorul lor se poate de transmis referinta la obiecte. Daca modificatorii ref si out indica la referinta, atunci insasi referinta se transmite prin referinta. Acest lucru permite modificarea obiectului in metoda, la care indica referinta. Sa analizam un exemplu, in care parametrul referinta de tip ref este folosit pentru a modifca obiectele, la care indica referintele:


//schimbare cu locul doua referinte

using System;

class RefSwap {
    int a, b;

    public RefSwap(int i, int j) {
        a = i;
        b = j;
    }

    public void Show() {
        Console.WriteLine("a: {0}, b: {1}", a, b);
    }

    //aceasta metoda modifica argumentele
    public void Swap(ref RefSwap ob1, ref RefSwap ob2) {
        RefSwap t;

        t = ob1;
        ob1 = ob2;
        ob2 = t;
    }
}


namespace RefSwapdemo
{
    class Program
    {
        static void Main(string[] args)
        {
            RefSwap x = new RefSwap(1, 2);
            RefSwap y = new RefSwap(3, 4);

            Console.WriteLine("x pina la apelare: ");
            x.Show();

            Console.WriteLine("y pina la apelare: ");
            y.Show();
            Console.WriteLine();

            //schimbarea obiectelor cu locul, la care se refera argumentele x si y
            x.Swap(ref x, ref y);
            Console.WriteLine("x dupa apelare: ");
            x.Show();

            Console.WriteLine("y dupa apelare: ");
            y.Show();

            Console.ReadKey(true);
        }
    }
}

Rezultat

x pina la apelare:
a: 1, b: 2
y pina la apelare:
a: 3, b: 4

x dupa apelare:
a: 3, b: 4
y dupa apelare:
a: 1, b: 2 

 

In acest exemplu in metoda Swap() se executa schimbarea obiectelor, la care fac referinta argumentele. Pina la apelul metodei Swap() argumentul x se refera la obiectul, care contine valorile 1 si 2, si y la obiectul cu valorile 3, 4. Dupa apelul metodei Swap(), argumentul x face referinta la obiectul, care contine valorile 3 si 4, iar y la obiectul care are valorile 1 si 2. Daca nu foloseam parametru de tip ref, atunci schimbarea in metoda Swap() nu ar fi avut efect in afara codului sau.