Risipa de key_press | Programare

Programare .Net | Tehnici de programare | Tutoriale | Lectii si exemple

Risipa de key_press | Programare - Programare .Net | Tehnici de programare | Tutoriale | Lectii si exemple

Namespaces (III)

In articolele Namespace-uri in programarea .Net I si Namespace-uri in programarea .Net II am facut o introducere a ceea ce inseamna un spatiu de nume, la ce foloseste si scurte prezentari asupra celor mai folosite spatii de nume din platforma .Net. In acest articol voi prezenta scenarii in care se poate afla un programator atunci cand foloseste un namespace.

Operatorul ::

Sa analizam urmatorul caz in care, in doua spatii de nume diferite, numele clasei este acelasi:

namespace Example
{
    public class Report
    {
        public string Message { get; set; }

        public Report()
        {
            Console.WriteLine("Report from Example namespace");
        }
    }
}


namespace ExampleII
{

    public class Report
    {
        public Report()
        {
            Console.WriteLine("Report from ExampleII namespace");
        }
    }

}

Daca incercam sa instantiem clasa Report, vom primi eroare:
‘Report’ is an ambiguous reference between ‘Example.Report’ and ‘ExampleII.Report’.
Solutia consta in crearea unui alias pentru a elimina ambiguitatea si a-i transmite compilatorului cu exactitate clasa pe care dorim sa o folosim. Concret, vom stabili un alias pentru spatiul de nume ExampleII.

using E = ExampleII;


            //ExampleII namespace
            E::Report rep  = new E::Report();
            //Report from Example namespace
            Report r = new Report();

Am folosit operator :: pentru a cauta identificatorul spatiului de nume.
Un alias pentru un spatiu de nume poate fi global. Asta inseamna ca nu se va cauta clasa in spatiul de nume cu alias, ci in spatiul de nume global.

extern alias

Un alt scenariu consta in existenta a doua dll-uri care au acelasi namespace. Acesta contine contine o clasa cu acelasi nume, dar implementata diferit in fiecare dll.

FirstClassLibrary.dll

namespace Example
{
    public class Report
    {
        public string Message { get; set; }

        public Report()
        {
            Console.WriteLine("First library report");
        }
    }
}

SecondLibrary.dll

namespace Example
{
    public class Report
    {
        public int Number { get; set; }
        
        public Report()
        {
            Console.WriteLine("Second library report");
        }
    }
}

Incercam sa instantiem clasa Report:

    class Program
    {
        static void Main(string[] args)
        {
            Report rep = new Report();                 
        }
    }

Evident, din cauza ambiguitatii, vom primi eroare:
The type ‘Example.Report’ exists in both ‘SecondLibrary.dll’ and ‘FirstLibrary.dll’ .
Si nici nu mai putem folosi alias ca in exemplul precedent, pentru ca spatiul de nume este acelasi.
Solutia vine din C# 2.0 din partea cuvantului cheie extern, care va fi aplicat unui alias. Pentru o declarare a unui alias extern se va crea un nivel radacina paralel cu spatiul de nume global.
Declaram extern alias.

extern alias FirstLibrary;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Example;

extern trebuie declarat inainte tuturor using-urilor. Altfel, primim eroare:
An extern alias declaration must precede all other elements defined in the namespace.

Daca vrem sa compilam in acest moment, vom primi eroarea: The extern alias ‘FirstLibraryAlias’ was not specified in a /reference option. Setam proprietatea Aliases pentru dll-ului referintiat. Revenind la problema de mai sus, vom presupune ca o sa ne referim la Report din SecondLibrary. Vom crea un alias pentru referinta la FirstLibrary.

Urmatorul codul nu va mai afisa eroare:

            //Second library report
            Report rep = new Report();

Modificatorul extern mai este folosit in declararea metodelor care sunt implementate extern, in cod unmanaged.

Spatii de nume imbricate

Presupunem ca avem urmatoarea structura:

namespace Outer
{
    class Agent
    {
        public Agent()
        {
            Console.WriteLine("outer namespace");
        }
    }

    namespace Middle
    {
         class Agent
        {
             public Agent()
            {
                Console.WriteLine("middle namespace");
            }
        }

        namespace Inner
        {
            class Agent
            {
                public Agent()
                {
                    Console.WriteLine("inner namespace");
                }
            }

             class Test
            {
                public Test()
                {
                    //test here
                }
            }
        }
    }
}

Numele din spatiile interioare ascund numele din spatiile exterioare. Daca instantiem clasa Agent, atunci compilatorul va crea referinta pentru cea din spatiul de nume cel mai apropiat (interior).

                public Test()
                {
                    //inner namespace
                    Agent a = new Agent();
                }

Pentru orice alta referire a clasei Agent, vom prefixa numele.

                public Test()
                {
                    //outer namespace
                    Outer.Agent a = new Outer.Agent();
                }

Un spatiu de nume poate primi un alias pentru a inlesni importul tipului dorit:

using M = Outer.Middle;

                    //middle namespace
                    M.Agent a = new M.Agent();

Un spatiu de nume poate fi declarat in fisiere diferite, din assembly-uri diferite. Singura conditie e ca numele tipurilor sa nu intre in conflict.
Spatiile de nume permit programatorului sa creeze un sistem in care sa isi organizeze codul. Un mod foarte bun de organizare a spatiilor de nume il constituie un sistem ierarhic. Ierarhia incepe cu nume cat mai generale si continua cu nume cat mai specifice pe masura ce coboara. Spatiile de nume imbricate ajuta la o mai buna organizare.

Category: Uncategorized

Your email address will not be published. Required fields are marked *

*