• Aucun résultat trouvé

[PDF] Cours complet sur les Assemblys .NET | Cours informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Cours complet sur les Assemblys .NET | Cours informatique"

Copied!
13
0
0

Texte intégral

(1)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND

Module .NET

Chapitre 3

Les Assemblys .NET

(2)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Page 2 sur 13

Contenu

Cours ... 3

3.1 - Définition d’un assembly .NET ... 3

3.2 - Private assembly ou assembly privé. ... 3

3.3 - Shared assembly ou assembly avec nom fort. ... 3

3.4 – Le Global Assembly Cache : GAC ... 4

3.5 - Structure d’une assembly .NET ... 4

3.6 – Les Espaces de noms ... 9

3.7 – Références externes ... 11

3.7.1 - Création d’une librairie ... 11

3.7.2 - Utiliser une référence externe ... 11

TP ... 13

VB.NET ... 13

(3)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND

Cours

3.1 - Définition d’un assembly .NET

Un assembly .NET est une collection de types et de ressources qui représente une unité logique de fonctionnalités. Un assembly .NET est un fichier qui contient du code CIL (Common Intermediate Language) et des informations supplémentaires afin de prévenir des erreurs de versions et d’accroitre la sécurité.

Le code CIL contenu dans l’assembly a été compilé par le compilateur VB.NET, C# (ou autre langage supporté par le framework .NET).

Le code CIL contenu dans l’assembly est ensuite compilé par le CLR en code machine exécutable lorsqu’il est chargé en mémoire. C’est pour cela que le compilateur du CLR est aussi appelé compilateur Just In Time ou juste à temps. L’assembly .NET est le standard pour les composants développés avec le .NET Microsoft.

Les assemblys .NET peuvent être ou non des exécutables, ce sont :

- Soit des applications (fichiers exécutables) d’extension .exe, aussi appelés PE (Portable Executable) - Soit des bibliothèques de types (Dynamic Link Librairies), d’extension .dll

Tous les assemblys contiennent:

La définition des types utilisés dans l’assembly Les informations de versions

Les métadonnées Le manifeste Le code IL

Il existe 2 sortes d’assemblys : private et shared.

3.2 - Private assembly ou assembly privé.

C’est le type par défaut lorsque l’on crée un assembly.

Ce type d’assembly est copié avec chaque assembly appelant dans le répertoire des assemblys à appeler : répertoire \bin dans une application ASP.NET.

répertoire \bin\debug ou \bin\release dans une application WinForm.

3.3 - Shared assembly ou assembly avec nom fort.

Ce type d’assembly est copié à un seul endroit (en général dans le Global Assembly Cache, le GAC).

Tous les assemblys d’une même application appelant une même assembly avec nom fort utilisent la même copie de cette assembly depuis son emplacement d’origine.

Ainsi, les assemblys avec nom fort ne sont pas copiés dans chacun des répertoires privés de chaque assembly appelant.

Un assembly avec nom fort possède un nom qualifié complet qui comprend son nom,

sa culture, sa clé publique, son numéro de version

optionnellement l’architecture de processeur.

MaLibrairie, Version=1.0.500.0, Culture=fr-FR, PublicKeyToken=b77a5c561934e089c La clé publique et les informations de version rendent donc pratiquement impossible la confusion entre 2 assemblys de même nom ou de même numéro de version.

Un assembly peut contenir dans un seul fichier ou être réparti dans plusieurs fichiers.

(4)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Page 4 sur 13

3.4 – Le Global Assembly Cache : GAC

Le Global Assembly Cache est un cache de code à l’échelle de l’ordinateur sur lequel est installé le CLR. Le Global Assembly Cache stocke les assemblys destinés à être partagés entre plusieurs applications sur l'ordinateur.

Vous ne devez partager des assemblys en les installant dans le Global Assembly Cache qu'en cas de nécessité. En règle générale, vous devez garder les dépendances d'assembly privées et rechercher les assemblys dans le répertoire de l'application, à moins que le partage d'un assembly soit explicitement requis.

On place un assembly dans le GAC :

soit par l’utilisation d’un programme d’installation prévu pour le GAC soit par l’utilitaire gacutil.exe fourni avec le SDK de Windows

soit par copier/coller avec l’explorateur Windows vers le répertoire du GAC Les assemblys déployés dans le Global Assembly Cache doivent avoir un nom fort.

Pour lister les assemblys contenus dans le GAC, on peut ouvrir une invite de commande Visual Studio (depuis le menu Démarrer, Visual Studio 2010, Visual Studio Tools) et lancer la commande suivante :

gacutil –l

Cette commande affiche plus de 2500 assemblys placés dans le GAC pour le framework .NET v4.0 ! Les principales librairies présentes dans le répertoire du GAC sont optimisées.

En effet, elles ont toutes été compilées en code natif lors de l’installation du framework sur la machine. Etant donné que le compilateur JIT optimise la compilation en code natif par rapport à la configuration de

l’ordinateur sur lequel il est installé, ces librairies sont donc compilées avec une optimisation pour l’ordinateur sur lequel elles ont été installées.

Une même librairie de même version pourra donc présenter, une fois compilée, un code natif différent d’un ordinateur à un autre.

3.5 - Structure d’une assembly .NET

Soit l’application console Module1.exe générée à partir du code source suivant vu auparavant: Public Class Appli1

Public Sub Main()

Console.WriteLine(« Bonjour ! ») Console.Read()

End Sub End Class

Compilation depuis VS ou avec ’vbc.exe module1.vb’

Le résultat est un exécutable standard Windows (un Portable Executable ou PE) dont la structure générale est la suivante : PE Header CLR Header Manifeste Métadonnées Code IL

Le PE Header contient les informations standard pour Windows et permet à Windows de reconnaitre l’assembly en tant que programme exécutable.

Dans cette section, figure un code qui indique qu’il faut charger la DLL mscoree.dll (MicroSoft Component Object Runtime Execution Engine). Cette DLL va ensuite déterminer quel type et version du CLR elle doit charger. Le CLR prend ensuite la main.

(5)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Il charge les métadonnées dans le CLR Header, recherche le point d’entrée (par exemple la fonction Main() ), compile le code IL de cette fonction avec son compilateur JIT en code natif du CPU et l’exécute.

Pendant la compilation du code, le JIT vérifie le code IL, d’où la notion de code managé.

S’il détecte des opérations non vérifiables telles que accès direct à la mémoire, il refusera d’exécuter l’application. Le C# permet de créer du code unsafe qui interdit au JIT d’effectuer ces contrôles. VB ne le permet pas.

L’utilitaire PEVerify.exe permet d’effectuer ces vérifications manuellement. Syntaxe : PEVerify.exe <nom du PE à tester>

Le CLR gère une table qui contient des pointeurs vers les fonctions inclues dans l’application.

Au chargement de l’application, le CLR remplit cette table avec des pointeurs vers le code IL de l’application.

Lorsqu’une fonction est appelée pour la première fois, le CLR la compile en code natif, puis remplace le contenu du pointeur correspondant non plus vers le code IL, mais vers le code compilé en code natif.

Lors des appels ultérieurs à cette fonction, le CLR appellera directement la version compilée.

C’est pour cette raison que l’on observe un temps d’exécution plus lent lors du premier appel à une fonction.

Table de pointeurs CLR • Methode1 • Methode2 • … Code IL Methode1 Methode2 … Code natif vide Table de pointeurs CLR • Methode1 • Methode2 • … Code IL Methode1 Methode2 … Code natif Methode1 Chargement de l’application 1er appel de Methode1

Pointeur Methode1 pointe vers code IL : Compilation de Methode1 en code natif

Remplacement du pointeur de Methode1

Appels suivants de Methode1

Pointeur Methode1 pointe vers code natif : Pas de compilation à effectuer

(6)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Page 6 sur 13

Il est possible de compiler l’application entière en code natif avec l’utilitaire ngen.exe. Cela permet d’éviter les pertes de vitesse dues à la première compilation de chaque fonction.

Cette opération peut être envisageable si l’application en question n’est utilisée que sur l’ordinateur sur lequel elle est compilée. En effet, comme nous l’avons vu à propos des librairies dans le chapitre du GAC, le CLR optimise le code natif par rapport à l’ordinateur sur lequel s’exécute la compilation.

Le fait de compiler l’application en code natif sur un ordinateur A et de copier cette image sur un ordinateur B annule toute l’optimisation qui pourrait être faite sur l’ordinateur B et peut même entrainer un plantage de l’application.

Le Manifeste est une synthèse des informations contenues dans les métadonnées. On peut visualiser son contenu grâce à l’outil ILDASM.exe

Le Manifeste indique :

La liste des fichiers qui composent l’assembly (1)

La liste des autres fichiers nécessaires au fonctionnement de l’assembly (2) La liste des types exportés de l’assembly

Le nom, la version et la culture de l’assembly Les informations de nom fort si l’assembly est signé Les informations sur le point d’entrée de l’assembly Pour tout assembly, il n’existe qu’un seul Manifeste.

Pour un assembly composé de plusieurs fichiers, un seul contiendra le manifeste. MonAssembly MonModule.exe Manifeste Métadonnées Code IL MesClasses1.dll Métadonnées Code IL MesClasses2.dll Métadonnées Code IL mscorlib mscorlib.dll Métadonnées Code IL mscorlib Microsoft.visualbasic.dll Métadonnées Code IL mscorlib System System.Deployment System.Windows.Forms System.Management System.Core System.Xml.Linq System.Drawing System.Runtime.Remoting

(7)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Les métadonnées contiennent des informations détaillées sur le contenu de l’assembly

Elles indiquent en détail :

La description de l’assembly (nom, version, …) telle que synthétisée dans le manifeste. La description des assemblys externes utilisés par l’assembly.

La description des fichiers composant l’assembly (si assembly multi-fichiers). La description de tous les types contenus dans l’assembly ainsi que leurs membres.

Toutes ces informations permettent au compilateur JIT d’effectuer les vérifications du code IL avant la compilation en code natif. Si le compilateur JIT détecte l’utilisation d’un type qui n’est pas représenté dans les métadonnées, il refusera systématiquement l’exécution de l’assembly.

Les métadonnées fixent en quelques sortes les règles que l’assembly doit respecter afin de pouvoir s’exécuter. On peut visualiser son contenu grâce à l’outil ILDASM.exe (menu Afficher, Méta-informations, Afficher)

Dans cette fenêtre, on peut rechercher la rubrique relative à notre méthode Main() grâce au menu de recherche. Prenons par exemple l’application TP010105ProjetCS dont le code principal est le suivant :

using System;

static class MaClasse

{

static void Main() {

Console.WriteLine("Salut en CS"); Console.Read();

} }

Ouvrons 1.5.2-UniqueCS dans ILDASM. La recherche de Main nous indique : TypeDef #1 (02000002)

--- TypDefName: MaClasse (02000002)

Flags : [NotPublic] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit] (00100000)

Extends : 01000001 [TypeRef] System.Object Method #1 (06000001) [ENTRYPOINT]

---

MethodName: Main (06000001)

Flags : [Private] [Static] [HideBySig] [ReuseSlot] (00000096) RVA : 0x00002050

ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT]

ReturnType: Void No arguments.

On retrouve bien les éléments que nous avons indiqué dans le code C# : Le nom de la méthode : Main

le type static de la fonction le type de retour void

(8)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Page 8 sur 13

Si on modifie explicitement ce modificateur d’accès en Public dans le code, on régénère le projet et on ouvre l’assembly avec ILDASM, nous aurons cette fois la rubrique suivante :

Method #1 (06000001) [ENTRYPOINT]

---

MethodName: Main (06000001)

Flags : [Public] [Static] [HideBySig] [ReuseSlot] (00000096) RVA : 0x00002050

ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT]

ReturnType: Void No arguments.

Dans l’application 1.5.2-UniqueCS, ajoutons maintenant une seconde méthode MaMethode: using System;

static class MaClasse

{

private static void Main() {

Console.WriteLine("Salut en CS"); Console.Read();

}

public Int32 MaMethode(Int16 x, Byte y) {

Int32 z = x + y; return z; }

}

Les métadonnées vues depuis ILDASM nous affichent maintenant : Method #1 (06000001) [ENTRYPOINT]

--- MethodName: Main (06000001)

Flags : [Private] [Static] [HideBySig] [ReuseSlot] (00000091) RVA : 0x00002050

ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] ReturnType: Void No arguments. Method #2 (06000002) --- MethodName: MaMethode (06000002)

Flags : [Public] [HideBySig] [ReuseSlot] (00000086) RVA : 0x00002064

ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] hasThis ReturnType: I4 2 Arguments Argument #1: I2 Argument #2: UI1 2 Parameters

(1) ParamToken : (08000001) Name : x flags: [none] (00000000) (2) ParamToken : (08000002) Name : y flags: [none] (00000000)

(9)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND On se rend donc bien compte que les métadonnées décrivent avec précision les types ainsi que la signature de chacune de leurs méthodes, de leurs paramètres et de leur valeur de retour.

Le détail de ses métadonnées rend donc la taille de cette section très importante.

On voit ici que les métadonnées occupent 4 à 5 fois plus de place que le code par lui-même !

La taille occupée par les métadonnées dans un assembly peut représenter plus de la moitié de la taille de l’assembly !

C’est le prix à payer pour disposer d’une application rendue plus sûre.

Les métadonnées sont aussi utilisées par Visual Studio afin de mettre à disposition l’IntelliSense. Grace aux

métadonnées, l’éditeur de code de VS connait à l’avance la signature des types et des fonctions que vous souhaitez utiliser.

3.6 – Les Espaces de noms

Les Espaces de noms ou Namespaces permettent de regrouper logiquement des types. Un Espaces de noms n’est pas un type.

Un Espaces de noms n’étant pas un type, on ne peut pas lui appliquer un modificateur d’accès. Il est traité comme s’il disposait d’un accès Public.

Si l’espace de noms n’est pas déclaré explicitement dans le code, un Espaces de noms par défaut est

automatiquement créé en prenant comme nom celui indiqué dans les propriétés du projet, par défaut avec le nom du projet en cours.

Il est possible d’imbriquer les Espaces de noms à l’intérieur d’autres Espaces de noms. Aucune limite n’est fixée quant au nombre de niveaux d’imbrication.

Déclaration d’un espace de noms VB Namespace MonEspaceDeNoms code … End Namespace C# namespace MonEspaceDeNoms { code … }

L’instruction Namespace ne peut être utilisée qu’au niveau d’un fichier ou d’un autre namespace.

On ne peut donc pas déclarer un Namespace à l’intérieur d’une classe, d’une structure, d’un module, d’une interface ou d’une procédure.

Prenons l’exemple d’un développeur qui crée un assembly dans lequel il expose des fonctions dédiées au dessin et d’autres aux fichiers, il pourrait très bien regrouper les fonctions correspondantes dans :

un Namespace nommé MesTypesGraphiques un Namespace nommé MesTypesFichiers. Le code pourrait ressembler à celui-ci : VB

(10)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Page 10 sur 13

Namespace MesTypesGraphiques Public Class MaClasseGraphique1

Public Shared Function MaFonctionGraphique() As Integer

Return 1 End Function End Class End Namespace C# namespace MesTypeGraphiques {

public class MaClasseGraphique1

{

public static int MaFonctionGraphique1() { return 1; } }

}

Pour utiliser les types définis dans les namespaces, on doit auparavant les référencer dans le fichier depuis lequel on effectue l’appel. Par Exemple :

VB

Imports [namespace de l’assembly].MesTypesGraphiques

Public Class Class2

Public Sub Test()

MaClasseGraphique1.MaFonctionGraphique() End Sub End Class C# using MesTypeGraphiques; class Class2 {

public void Test() {

MaClasseGraphique1.MaFonctionGraphique1(); }

}

Dans les métadonnées, la fonction MaFonctionGraphique1 est maintenant préfixée par l’espace de noms MesTypesGraphiques.

On peut contrôler cela avec ILDASM : TypeDef #3 (02000004)

---

TypDefName: MesTypeGraphiques.MaClasseGraphique1 (02000004)

Flags : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit] (00100001)

Extends : 01000001 [TypeRef] System.Object Method #1 (06000006)

--- MethodName: MaFonctionGraphique1 (06000006)

Flags : [Public] [Static] [HideBySig] [ReuseSlot] (00000096) RVA : 0x00002094

ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT]

ReturnType: I4 No arguments.

(11)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Afin d’éviter les confusions au niveau des espaces de noms, Microsoft préconise d’utiliser un nom unique comme nom de namespace principal.

Exemple : MaSociete.ThemePrincipal.ThemeSecondaire…

Les types appartenant à un même espace de noms peuvent être compilés dans des assemblys différents.

Afin de pouvoir utiliser les types exposés dans l’espace de noms MaSociete.Fichiers, il faut ajouter le fichier

Assembly1.dll dans les références du projet et référencer (par la directive using en C# ou Imports en VB) l’espace de nom MaSociete.Fichiers dans chaque fichier ou l’ou souhaite utiliser les types F1, F2 ou F3.

Afin de pouvoir utiliser les types G1 à G5 exposés dans l’espace de noms MaSociete.Graphisme, il faut ajouter les 2 fichiers Assembly1.dll et Assembly2.dll dans les références du projet et référencer (par la directive using en C# ou Imports en VB) l’espace de nom MaSociete.Graphisme dans chaque fichier ou l’ou souhaite utiliser les types G1 à G5.

3.7 – Références externes

3.7.1 - Création d’une librairie

Pour créer une librairie de classes, on a 2 solutions :

Créer le projet en utilisant le modèle librairie de classes

Soit en modifiant les propriétés du projet actuel (onglet Application, type de sortie).

3.7.2 - Utiliser une référence externe

Pour pouvoir utiliser une librairie, l’assembly appelant à d’abord besoin de connaitre l’emplacement du fichier qui contient l’assembly de cette librairie.

On doit donc :

Référencer l’assembly au niveau de l’assembly appelant

Référencer les espaces de noms à utiliser au niveau du fichier source appelant Assembly1.dll MaSociete.Graphisme Class G1 Class G2 Class G3 MaSociete.Fichiers Class F1 Class F2 Class F3 Assembly2.dll MaSociete.Graphisme Class G4 Class G5 … MaSociete.Modeles Class M1 Class M2 …

(12)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND Page 12 sur 13

Référencer l’assembly au niveau de l’assembly appelant

En VB, on affiche les propriétés du projet, Onglet Références et clic sur ajouter

En C#, clic droit sur le dossier Références dans l’explorateur de solutions, puis ajouter une référence On a ensuite le choix entre 4 sortes de référencement :

.NET

Affiche la liste de toutes les librairies présentes dans le framework. Ces librairies sont placées dans le GAC. COM

Affiche la liste de tous les composants COM disponibles sur le système. Cette liste ne se limite donc pas aux composants Microsoft (ex : Adobe Acrobat Type Library)

Projets

Affiche la liste des projets contenus dans la solution Parcourir

Permet de charger explicitement un assembly situé sur le disque dur.

A ce stade, le compilateur sait comment accéder à l’assembly. Cette information sera stockée dans les métadonnées et le manifeste comme nous l’avons vu auparavant.

S’il s’agit d’une référence externe qui n’est pas dans le GAC, le fichier correspondant sera copié dans le répertoire des références de l’application :

Si projet Console ou WinForms, dans le repertoire bin/debug ou bin/release Si projet application Web, dans le répertoire bin

Référencer les espaces de noms à utiliser au niveau du fichier source appelant

Pour que le code contenu dans un fichier source puisse accéder aux types contenus dans l’assembly externe, il faut ajouter explicitement au début de ce fichier le nom du namespace contenu dans cet assembly qui contient les types que l’on souhaite utiliser.

On déclare cela avec les directives suivantes En VB : Imports espace_de_nom

En C# : Using espace_de_nom ;

Les types définis dans l’espace de nom référencé par ces directives permettent ensuite d’utiliser les types qu’il contient.

Une référence pouvant contenir plusieurs espaces de noms, il faut ajouter une directive Imports ou Using pour chacun des espaces de noms que l’on souhaite utiliser.

(13)

Licence METINET : Concepteur et Gestionnaire de Sites Internet Christian ALLEMAND

TP

VB.NET

Créer une solution TP0301VB avec un projet application console TP0301VBApp et un projet librairie de classe TP0301VBLib (avec 1 classe publique qui contient 1 champ public)

Référencer la librairie dans l’appli TP0301VBApp par l’option Projet.

Modifier la librairie TP0301VBLib (ajouter un champ), générer et voir les conséquences sur l’appli.

Créer une solution TP0302VB avec seulement une appli TP0302VBApp qui appelle la librairie TP0301VBLib par l’option Parcourir.

Modifier la librairie TP0301VBLib, générer et voir les conséquences sur l’appli.

Dans l’appli TP0302VBApp, tester l’ajout d’une référence COM (exemple Adobe Acrobat Type Library ).

Pendant l’écriture de la directive Imports (ou using en C#), observer que VS nous propose l’arborescence des espaces de noms de cette librairie. Importer l’espace de noms Acrobat.PDDocFlags ou autre si pas présent.

Créer une variable qui va utiliser un type contenu dans cet espace de noms et l’afficher.

C#

Créer une solution TP0301CS avec un projet application console TP0301CSApp et un projet librairie de classe TP0301CSLib (avec 1 classe publique qui contient 1 champ public)

Référencer la librairie dans l’appli TP0301CSApp par l’option Projet.

Modifier la librairie TP0301CSLib (ajouter un champ), générer et voir les conséquences sur l’appli.

Créer une solution TP0302CS avec seulement une appli TP0302CSApp qui appelle la librairie TP0301CSLib par l’option Parcourir.

Modifier la librairie TP0301CSLib, générer et voir les conséquences sur l’appli.

Dans l’appli TP0302CSApp, tester l’ajout d’une référence COM (exemple Adobe Acrobat Type Library ).

Pendant l’écriture de la directive Imports (ou using en C#), observer que VS nous propose l’arborescence des espaces de noms de cette librairie. Importer l’espace de noms Acrobat.PDDocFlags ou autre si pas présent.

Figure

Table de pointeurs CLR  • Methode1  • Methode2  • …  Code IL     Methode1    Methode2 …  Code natif     vide  Table de pointeurs CLR  • Methode1  • Methode2  • …  Code IL     Methode1    Methode2    …  Code natif     Methode1 Chargement de l’application 1e

Références

Documents relatifs

Si des paroles ont été mises par écrit, c’est dans la perspective d’être postérieurement (re)lues. Dans la complexité des études épigraphiques, cette évidence est

ce qui fut une véritable révolution au tout début de cette métallurgie, quand, d'une activité à faible production durant le Chalcolithique et le début de l'âge du Bronze, on passe

Sebastião Caetano Fazenda Progresso Preguiçosa Palmeira Bela Vista Barra do Laranjal Laranjal Lajinha l Paraju Sobreiro Cafundó Itaimbé Fazenda Panorama Alto Sobreiro Itaguaçu

O manejo inadequado dos solos impede a sustentabilidade do ecossistema (ALVARENGA 2002) e as bacias hidrográficas são unidades físicas que podem ser

Além da bananeira, o vírus também causa doença em mais de 800 espécies de plantas, dentre as quais destacam-se o pepino, tomate, pimentão, abóbora, melão,

Le Nil trace un chapelet de villes dans le désert, alors que le Delta montre une organisation beaucoup plus régulière.. On retrouve quelques petites villes le long des côtes

Nous savons, grâce à la psychologie, que la cohésion de quelque groupe que ce soit, la solidarité de groupe, dépend tant des attitudes positives que négatives de ses membres.

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des