Sunteți pe pagina 1din 24

CLR. AppDomain.

Reflection
Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Creare CLR, AppDomain, si Reflection


Metadata: una din cele mai importante trasaturi ale .NET-ului
Metadata descrie tipul unui camp precum si metodele asociate acestuia.
Metadata:
contine informatia de care un tip de data are nevoie pentru a se defini;
este folosita de GC pentru a determina daca un obiect mai este valid in heap;
este folosita de utilitarele de dezvoltare pentru a construi help senzitiv utilizat in
momentul scrierii codului (vezi Intellisense);
este folosita in procesul de serializare si deserializare al obiectelor.
Actiunea de examinare a metadatei se numeste reflection.
Reflection permite dezvoltatorilor de a construi in mod dinamic aplicatii extensibile.
De exemplu, oricine poate scrie un tip de data si sa-l impacheteze intr-un assembly.
Cand altcineva foloseste acest tip, datorita informatiilor din metadata, un mediu de
dezvoltare (Visual Studio .NET, etc.) poate integra acest tip in cadrul proiectului si sa
afiseze proprietatile expuse de acest tip.
CLR modalitati de instantiere
Cadrul de lucru .NET ruleaza deasupra sistemului de operare. Acest lucru inseamna ca
.NET trebuie sa foloseasca tehnologii pe care Windows sa le inteleaga.
CLR a fost implementat ca un server COM continut intr-un DLL ; deci acesta are o
interfata COM standard, are atribuit un GUID. Toate aceste informatii sunt scrise in
registri in momentul instalarii serverului COM.
Definitiile pentru acest server se gasesc in MSCorEE.h (definitia interfetei
ICorRuntimeHost si definitiile GUID-urilor).
Pentru a crea o instanta a acestui server va trebui sa utilizam functia CorBindToRuntimeEx
in loc de functia CoCreateInstance.
Functia CorBindToRuntimeEx este implementata in MSCorEE.dll ce se gaseste in
subdirectorul System32 al sistemului de operare, dar serverul nu este in acest DLL.
Aceasta biblioteca este folosita pentru a determina versiunea corecta a CLR-ului ce se va
crea. Biblioteca MScorWks.dll contine versiunea pentru statii de lucru, iar MSCorSvr.dll
contine versiunea pentru server.
O aplicatie poate suprascrie valorile implicite necesare pentru crearea serverului plasand
informatii intr-un fisier de configurare XML, ca in exemplul urmator :
<configuration>
<startup>
<requiredRuntime version="v1.0.0.0" safemode="true"/>
</startup>
</configuration>

Daca safemode = false, atunci se incarca versiunea de CLR cea mai recenta ce este
compatibila cu versiunea aplicatiei noastre.
Ioan Asiminoaei

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

MS determina ce versiune de CLR este compatibila cu alte versiuni prin crearea de


informatii in registri. Aceste se gasesc sub cheia
HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\Policy
Functia CorBindToRuntimeEx returneaza un pointer la interfata unmanaged
ICorRuntimeHost (definita in MSCorEE.h). Aplicatia poate apela metodele definte de
aceasta interfata pentru a initializa CLR.
Un singur proces poate crea numai o instanta a unui server COM CLR.
Dintre multele actiuni efectuate in timpul initializarii CLR, enumeram:
Se creaza zona heap managed in care vor fi alocate obiectele referinta si pe care o
va gestiona GC.
Se creaza un thread pool folosit de orice tip managed ale carui assembly sunt
incarcati in proces.
Se creaza un AppDomain. Un AppDomain poate fi asimilat ca un container logic
pentru o multime de assemblies. Primul AppDomain creat se numeste AppDomain
implicit. Acest AppDomain implicit este distrus cand procesul Windows se
termina. CLR poate crea mai multe AppDomain, in afara de cel implicit.
AppDomain
Sunt reprezentate de obiecte AppDomain.
Un proces poate contine mai multe AppDomain, iar un AppDomain poate contine unul sau
mai multe fire.
AppDomain sunt create cu metoda CreateDomain.
Instantele AppDomain sunt folosite pentru a incarca si executa assemblies.
Clasa AppDomain implementeaza o multime de evenimente ce permite aplicatiilor sa
raspunda cand un assembly este incarcat, cand un AppDomain este descarcat sau cand este
lansata o exceptie necunoscuta.
Aceasta clasa implementeaza MarshalByRefObject, si interfetele _AppDomain si
IEvidenceFactory.
Interfata _AppDomain implementeaza o multime de evenimente ce permit aplicatiilor sa
raspunda cand un assembly este incarcat, un AppDomain va fi descarcat sau sa trateze
exceptii.
MarshalByRefObject este clasa de baza pentru obiectele ce comunica in afara
frontierelor aplicatiei prin schimbul de mesage folosind un proxy.
Obiectele ce nu sunt mostenite din MarshalByRefObject sunt implicit transferate
prin valoare.
Obiectele MarshalByRefObject sunt accesate direct in interiorul domeniului.
Pentru a realiza acest lucru se foloseste un proxy, ce este pasat aplicatiei remote.
Toate apelurile se realizeaza prin cadrul acestui proxy (tehnica asemanatoare si la
COM/DCOM).

Ioan Asiminoaei

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Public Properties

BaseDirectory
CurrentDomain
DynamicDirectory
Evidence
FriendlyName

Gets the base directory that the assembly resolver used to


probe for assemblies.
Gets the current application domain for the current Thread.
Gets the directory that the assembly resolver used to probe
for dynamically-created assemblies.
Gets the Evidence associated with this application domain
that is used as input to the security policy.
Gets the friendly name of this application domain.

Supported by the .NET


Compact Framework.
RelativeSearchPath
SetupInformation
ShadowCopyFiles

Gets the path relative to the base directory where the


assembly resolver should probe for private assemblies.
Gets the application domain configuration information for
this instance.
Gets an indication whether all assemblies loaded in the
application domain are shadow copied.

Public Methods

AppendPrivatePath
ClearPrivatePath
ClearShadowCopyPath
CreateComInstanceFrom
CreateDomain

Appends the specified name of the directory to the


private path.
Resets the path that specifies the location of private
assemblies to the empty string ("").
Resets the list of directories containing shadow copied
assemblies to the empty string ("").
Overloaded.
Overloaded. Creates a new application domain.

Supported by the .NET


Compact Framework.
Overloaded. Creates a new instance of a specified
type defined in a specified assembly.
Overloaded. Creates a new instance of a specified
CreateInstanceAndUnwrap
type.
Overloaded.
Creates a new instance of a specified
CreateInstanceFrom
type defined in the specified assembly file.
Overloaded. Creates a new instance of a specified
CreateInstanceFromAndUnwrap type defined in the specified assembly file.
CreateObjRef (inherited from Creates an object that contains all the relevant
information required to generate a proxy used to
MarshalByRefObject)
communicate with a remote object.
Overloaded. Defines a dynamic assembly in the
DefineDynamicAssembly
current application domain.
Executes
the code in another application domain that
DoCallBack
is identified by the specified delegate.
Overloaded. Determines whether two Object
Equals (inherited from
CreateInstance

Ioan Asiminoaei

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi
Object)

21.01.2007

instances are equal.

Supported by the .NET


Compact Framework.
ExecuteAssembly

Overloaded. Executes the assembly contained in the


specified file.

Supported by the .NET


Compact Framework.
GetAssemblies
GetCurrentThreadId

Gets the assemblies that have been loaded into this


application domain.
Gets the current thread identifier.

Gets the value stored in the current application


domain for the specified data name.
GetHashCode (inherited from Serves as a hash function for a particular type,
suitable for use in hashing algorithms and data
Object)
structures like a hash table.
Supported by the .NET
GetData

Compact Framework.
GetLifetimeService (inherited Retrieves the current lifetime service object that
controls the lifetime policy for this instance.
from MarshalByRefObject)
Gets the Type of the current instance.
GetType (inherited from
Object)
Supported by the .NET
Compact Framework.

SetShadowCopyFiles

Overridden. Gives the AppDomain an infinite lifetime


by preventing a lease from being created.
Indicates whether this application domain is
unloading, and the objects it contains are being
finalized by the common language runtime.
Overloaded. Loads an Assembly into this application
domain.
Establishes the security policy level for this
application domain.
Establishes the specified directory path as the location
where assemblies are shadow copied.
Assigns the specified value to the specified application
domain property.
Establishes the specified directory path as the location
where dynamically generated files are stored and
accessed.
Specifies how principal and identity objects should be
attached to a thread if the thread attempts to bind to
a principal while executing in this application domain.
Turns on shadow copying.

SetShadowCopyPath

Establishes the specified directory path as the location

InitializeLifetimeService
IsFinalizingForUnload

Load
SetAppDomainPolicy
SetCachePath
SetData
SetDynamicBase

SetPrincipalPolicy

Ioan Asiminoaei

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

of assemblies to be shadow copied.


Sets the default principal object to be attached to
threads if they attempt to bind to a principal while
executing in this application domain.
Overridden. Obtains the String representation of this
instance.

SetThreadPrincipal

ToString
Supported by the .NET
Compact Framework.

Unloads the specified application domain.

Unload
Public Events

AssemblyLoad
AssemblyResolve
DomainUnload
ProcessExit
ResourceResolve
TypeResolve
UnhandledException

Occurs when an assembly is loaded.


Occurs when the resolution of an assembly fails.
Occurs when an AppDomain is about to be unloaded.
Occurs on the default application domain when the default
application domain's parent process exits.
Occurs when the resolution of a resource fails.
Occurs when the resolution of a type fails.
Occurs when an exception is not caught by an event
handler.

Protected Methods

Finalize (inherited from


Object)

Overridden. Allows an Object to attempt to free


resources and perform other cleanup operations
before the Object is reclaimed by garbage collection.

Supported by the .NET Compact


In C# and C++, finalizers are expressed using

Framework.

destructor syntax.
MemberwiseClone (inherited Creates a shallow copy of the current Object.
from Object)
Supported by the .NET Compact
Framework.

Exemplu pentru tratarea unui eveniment.

AppDomain.AssemblyLoad Event
[C#]
public virtual event AssemblyLoadEventHandler AssemblyLoad;
Event Data
Functia ce trateaza evenimentul primeste un argument de tip AssemblyLoadEventArgs
ce contine informatii despre acest eveniment.
Proprietatea AssemblyLoadEventArgs furnizeaza informatii specifice pentru acest
eveniment.
Property

Ioan Asiminoaei

Description

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi
LoadedAssembly

21.01.2007

Gets an Assembly that represents the


currently loaded assembly.

Remarks
The AssemblyLoadEventHandler delegate for this event indicates what assembly was
loaded.
To register an event handler for this event, you must have the permissions described
in the Permissions section. If you do not have the appropriate permissions, a
SecurityException occurs.
For more information about handling events, see Consuming Events.
Example
[Visual Basic, C#, C++] For this code example to run, you must provide the fully
qualified assembly name.
[C#]
using System;
using System.Reflection;
class Test {
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyLoad += new
AssemblyLoadEventHandler(MyAssemblyLoadEventHandler);
PrintLoadedAssemblies(currentDomain);
// Lists mscorlib and this assembly
// You must supply a valid fully qualified assembly name here.
currentDomain.CreateInstance("System.Windows.Forms, Version,
Culture, PublicKeyToken", "System.Windows.Forms.TextBox");
// Loads System, System.Drawing, System.Windows.Forms
PrintLoadedAssemblies(currentDomain);
// Lists all five assemblies
}
static void PrintLoadedAssemblies(AppDomain domain)
{
Console.WriteLine("LOADED ASSEMBLIES:");
foreach (Assembly a in domain.GetAssemblies())
{
Console.WriteLine(a.FullName);
}
Console.WriteLine();
}
static void MyAssemblyLoadEventHandler(object sender,
AssemblyLoadEventArgs args)
{
Console.WriteLine("ASSEMBLY LOADED: " +
args.LoadedAssembly.FullName);
Console.WriteLine();
}
}

Ioan Asiminoaei

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

AppDomain.CreateInstanceAndUnwrap Method
Creates a new instance of a specified type.
Overload List
Creates a new instance of the specified type. Parameters specify the assembly where
the type is defined, and the name of the type.
[C#] public object CreateInstanceAndUnwrap(string, string);
Creates a new instance of the specified type. Parameters specify the assembly where
the type is defined, the name of the type, and an array of activation attributes.
[C#] public object CreateInstanceAndUnwrap(string, string, object[]);
Creates a new instance of the specified type. Parameters specify the name of the
type, and how it is found and created.
[C#] public object CreateInstanceAndUnwrap(string, string, bool, BindingFlags,
Binder, object[], CultureInfo, object[], Evidence);
[C#]
public object CreateInstanceAndUnwrap(
string assemblyName,
string typeName,
bool ignoreCase,
BindingFlags bindingAttr,
Binder binder,
object[] args,
CultureInfo culture,
object[] activationAttributes,
Evidence securityAttributes
);
Parametri
assemblyName = nume assembly.
typeName = numele tipului cerut (calificat complet).
ignoreCase = valoare booleana; specifica daca se executa cautare case-sensitive sau
nu.
bindingAttr = o combinatie de flaguri ce afecteaza cautarea constructorului pentru
typeName.
binder = un obiect ce permite legarea, verificarea tipurilor argumentelor, invocarea
membrilor si regasirea obiectelor MemberInfo folosind reflection. Daca binder este
null, atunci se foloseste legarea implicita.
args = argumentele ce trebuiesc pasate constructorului. Daca se doreste apelarea
constructorului implicit, args trebuie sa fie null.
culture = obiect folosit in verificarea tipurilor.
activationAttributes = un tablou de atribute ce pot participa in procesul de invocare.
securityAttributes = atribute de securitate pentru typeName.
Valoarea returnata reprezinta o instanta a obiectului specificat de typeName.
Exceptions
Exception Type
ArgumentNullException

Ioan Asiminoaei

Condition
assemblyName or typeName is a null

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi
MissingMethodException
TypeLoadException
FileNotFoundException
MethodAccessException
NotSupportedException

SecurityException

AppDomainUnloadedException

21.01.2007

reference (Nothing in Visual Basic).


No matching constructor was found.
typename was not found in
assemblyName.
assemblyName was not found.
The caller does not have permission to call
this constructor.
The caller cannot provide activation
attributes for an object that does not
inherit from MarshalByRefObject.
The caller does not have the correct
permissions. See the requirements
section.
Operations are attempted on an unloaded
application domain.

Aceasta metoad combina CreateInstance si ObjectHandle.Unwrap si apeleaza


constructorul implicit pentru typeName.

Exemplu
[C#]
using System;
using System.Reflection;
class Test {
static void Main() {
InstantiateINT32(false);
InstantiateINT32(true);
}

// Failed!
// OK!

static void InstantiateINT32(bool ignoreCase) {


try {
AppDomain currentDomain = AppDomain.CurrentDomain;
object instance = currentDomain.CreateInstanceAndUnwrap(
"mscorlib",
"SYSTEM.INT32",
ignoreCase,
BindingFlags.Default,
null,
null,
null,
null,
null
);
Console.WriteLine(instance.GetType());
} catch (TypeLoadException e) {
Console.WriteLine(e.Message);
}
}
}

Exemplu pentru CreateDomain (vezi MS). Importante sunt etapele de creare, care
urmaresc prototipul metodei CreateDomain ce va fi folosita.

Ioan Asiminoaei

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

// Set up the AppDomainSetup


AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = "(some directory)";
setup.ConfigurationFile = "(some file)";
// Set up the Evidence
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence evidence = new Evidence(baseEvidence);
evidence.AddAssembly("(some assembly)");
evidence.AddHost("(some host)");
// Create the AppDomain
AppDomain newDomain = AppDomain.CreateDomain("newDomain", evidence,
setup);

Clasa AppDomainSetup = Contine informatii pentru legare assembly ce pot fi


adaugate la o instanta a unui AppDomain.
Membrii acestei clase sunt utilizati cu metodele AppDomain.GetData si
AppDomain.SetData pentru a identifica data System.AppDomain ce trebuie utilizata.
AppDomainSetup Members
AppDomainSetup overview
Public Constructors
AppDomainSetup Constructor

Initializes a new instance of the


AppDomainSetup class.

Public Properties
ApplicationBase
ApplicationName
CachePath
ConfigurationFile
DisallowBindingRedirects
DisallowCodeDownload

DisallowPublisherPolicy

DynamicBase
LicenseFile
LoaderOptimization
PrivateBinPath

PrivateBinPathProbe

Ioan Asiminoaei

Gets or sets the name of the directory containing


the application.
Gets or sets the name of the application.
Gets or sets the name of an area specific to the
application where files are shadow copied.
Gets or sets the name of the configuration file for
an application domain.
Gets or sets a value indicating if an application
domain allows assembly binding redirection.
Gets or sets a value indicating whether HTTP
download of assemblies is allowed for an
application domain.
Gets or sets a value indicating whether the
publisher policy section of the configuration file is
applied to an application domain.
Gets or sets the directory where dynamically
generated files are stored and accessed.
Gets or sets the location of the license file
associated with this domain.
Specifies the optimization policy used to load an
executable.
Gets or sets the list of directories that is combined
with the ApplicationBase directory to probe for
private assemblies.
Gets or sets the private binary directory path used

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

to locate an application.
Gets or sets the names of the directories containing
assemblies to be shadow copied.
Gets or sets a string that indicates whether shadow
copying is turned on or off.

ShadowCopyDirectories
ShadowCopyFiles

Clasa Evidence
Defineste multimea de informatii ce constituie intrare pentru deciziile politicii de
securitate. Clasa nu poate fi mostenita.
Obiectele de orice tip ce sunt recunoscute de politica de securitate reprezinta
evidence.
Politica de securitate este compusa din grupuri de cod; un assembly particular
(unitatea de baza pentru acordarea drepturilor de securitate) este un membru al unui
cod de grup daca satisface conditiile membrilor grupului de cod.
Evidence este multimea intrarilor pentru aceasta politica de securitate folosita
pentru a determina carui grup de cod ii apartine un anumit assembly.
Clasa Evidence este o colectie (vezi ICollection) ce pastreaza multimea obiectelor ce
reprezinta evidence.
Aceasta clasa tine doua multimi ce corespund sursei evidence : host evidence si
assembly evidence.
Cand se evalueaza permisiunile unui cod se folosesc aceste doua multimi.

Host evidence is provided by the host, and can only be provided by hosts
that have been granted the ControlEvidence permission. Typically, this is evidence
of the origin of the code and digital signatures on the assembly. Evidence about
origin typically includes Url, Site, and Zone evidence. Signatures refer to software
publisher (AuthentiCode X.509v3 signature) and strong name identities. Both
kinds of digital signature-based identity are built into the assembly, but must be
validated and passed to policy by the host; when loaded, the security system
verifies the signature. The system then creates the appropriate evidence and
passes it to policy only if the corresponding signature is valid.

Assembly evidence is part of the assembly itself. Developers or


administrators can attach custom evidence to the assembly to extend the set of
evidence for policy. Assembly evidence can only be added at the time of assembly
generation, which occurs before the assembly is signed. The default policy of the
security system ignores assembly-provided evidence, but policy can be extended
to accept it.

Public Constructors

Evidence Constructor
Supported by the .NET Compact
Framework.

Overloaded. Initializes a new instance of


the Evidence class.

Public Properties

Count

Gets the number of evidence objects in the evidence set.

IsReadOnly

Gets a value indicating whether the evidence set is readonly.


Gets a value indicating whether the evidence set is threadsafe.
Gets or sets a value indicating whether the evidence is

IsSynchronized
Locked

Ioan Asiminoaei

10

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi
SyncRoot

21.01.2007

locked.
Gets the synchronization root.

Public Methods

AddAssembly
AddHost
CopyTo
Equals (inherited from Object)

Adds the specified assembly evidence to the


evidence set.
Adds the specified evidence supplied by the host
to the evidence set.
Copies evidence objects to an Array.
Overloaded. Determines whether two Object
instances are equal.

Supported by the .NET Compact


Framework.
GetAssemblyEnumerator

Enumerates evidence provided by the assembly.

GetEnumerator

Enumerates all evidence in the set, both that


provided by the host and that provided by the
assembly.
Serves as a hash function for a particular type,
suitable for use in hashing algorithms and data
structures like a hash table.

GetHashCode (inherited from


Object)
Supported by the .NET Compact
Framework.
GetHostEnumerator

Enumerates evidence supplied by the host.

GetType (inherited from Object) Gets the Type of the current instance.
Supported by the .NET Compact
Framework.
Merges the specified evidence set into the current
evidence set.
ToString (inherited from Object) Returns a String that represents the current
Object.
Supported by the .NET Compact
Merge

Framework.

Protected Methods

Finalize (inherited from Object)


Supported by the .NET Compact
Framework.

MemberwiseClone (inherited from


Object)
Supported by the .NET Compact
Framework.

Ioan Asiminoaei

Overridden. Allows an Object to attempt to


free resources and perform other cleanup
operations before the Object is reclaimed
by garbage collection.
In C# and C++, finalizers are expressed
using destructor syntax.
Creates a shallow copy of the current
Object.

11

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

AppDomain se caracterizeaza prin:


Sunt izolate unele de altele un AppDomain nu poate vedea obiectele create de alt
AppDomain dar poate comunica cu tipuri si obiecte din alte AppDomain. Aceasta
caracteristica face ca AppDomain sa poata fi descarcate din proces. CLR nu are
posibilitatea de a descarca un singur assembly. Assemblies vor fi descrcati odata cu
AppDomain care le-a incarcat.
Pot fi configurate si securizate individual. Astfel se determina drepturile maxime
atribuite unui assembly ce ruleaza intr-un AppDomain. Putem gestiona securitatea
unui AppDomain folosind metoda SetAppDomainPolicy.
Clasa System.AppDomainSetup ne permite sa definim si sa interogam setarile unui
AppDomain. Aceste setari includ urmatoarele :
ApplicationName un string folosit pentru a identifica un AppDomain.
ApplicationBase un director unde CLR va cauta assemblies.
PrivateBinPath o multime de directoare unde CLR va cauta sa localizeze assmblies cu
nume slabe .
ConfigurationFile numele caii unui fisier de configurare ce contine reguli pe care CLR
le va utiliza pentru a localiza assemblies. Fisierul contine de asemenea setari pentru
remoting, aplicatii Web, etc.
LoaderOptimization un flag ce indica modul cum CLR trateaza assemblies incarcati :
ca domain neutral sau single-domain .
Observatie: S-ar putea sa fie periculos sa se ruleze mai multe aplicatii unmanaged intrun singur proces, pentru ca acestea pot avea acces la datele si codul din cadrul celeilalte
aplicatii.
Accesarea obiectelor in afara unui AppDomain
Codul dintr-un domeniu poate comunica cu tipuri si obiecte continute in alte domenii.
Majoritatea tipurilor sunt transferate prin valoare in cadrul altor domenii. Obiectul este
serializat in cadrul unui bloc de memorie si apoi transmis altui domeniu. Domeniul ce
primeste acest obiect il va deserializa. Domeniul destinatie nu are acces la obiectul
original.
Obiectele transmise prin valoare trebuie sa aiba atributul System.Serializable.
Deserializarea obiectului are ca efect incarcarea de catre CLR a tipului de assembly
necesar. Daca CLR nu poate incarca acel assembly, atunci deserializarea nu are loc si va fi
emisa o exceptie.
Tipurile ce sunt derivate din System.MarshalByRefObject pot fi de asemenea transmise
altor domenii. In acest caz se transmite o referinta la obiect. Obiectul original ramine in
domeniul sursa (acolo unde a fost creat obiectul).
Nu exista o corespondenta de 1-1 intre fire si AppDomain. Cand se executa un fir dintr-un
doemniu in alt domeniu, firul tranziteaza intre cele doua AppDomain, deci acesta este
executat in mod sincron. La un moment dat, un fir este considerat sa fie exact intr-un
domeniu.
Putem apela metoda statica GetDomain din System.Threading.Thread pentru a obtine o
referinta la un obiect System.AppDomain si a identifica domeniul unde se executa firul.
Cand un AppDomain este descarcat, toate firele din acest domeniu vor fi terminate, CLRul fortand o exceptie de tipul ThreadAbortException, de asemenea vor fi descarcate si
assemblies continuti in AppDomain.

Ioan Asiminoaei

12

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Evenimente AppDomain
Evenimentele pe care le putem trata sunt:
AssemblyLoad apare cand CLR incarca un assembly intr-un domeniu. Functia ce trateaza
evenimentul primeste un obiect System.Reflection.Assembly ce identifica assembly
incarcat.
DomainUnload - apare inainte ca AppDomain sa fie descarcat. Evenimentul nu apare
cand procesul ce contine AppDomain este terminat.
ProcessExit - apare inainte ca procesul sa se termine. Evenimentul este lansat numai
pentru AppDomain implicit.
UnhandledException - emis cand apare o exceptie intr-un AppDomain.
AssemblyResolve apare cand CLR nu poate localiza un assembly cerut de un domeniu.
Functia ce trateaza evenimentul primeste un string ce identifica numele assembly lipsa.
ResourceResolve acelasi lucru ca la AssemblyResolve, numai ca este vorba de o resursa.
TypeResolve Acelasi lucru ca mai sus, numai ca este vorba de un tip de data.
Din nou despre Reflection
Metadata este constituita dintr-o multime de tabele. Cand construim un assembly sau un
modul, compilatorul creaza o serie de tabele: tabela de definitie a tipurilor, tabela de
definitie a campurilor, tabela de definitie a metodelor, etc.
Spatiul de nume System.Reflection din FCL contine mai multe tipuri ce permit sa scriem
cod ce obtine informatii din aceste tabele. Tipurile din acest spatiu de nume ofera un
model obiect peste metadata continuta in assembly sau modul.
Cu ajutorul acestor tipuri putem enumera toate tipurile dintr-o tabela de definitie a
tipurilor. Pentru fiiecare tip putem obtine tipul de baza, ce interfete implementeaza.
De asemenea putem obtine campurile, metodele, proprietatile, atributele si evenimentele
unui tip.
Metoda reflection este cel mai des folosita cu clasele de biblioteci pentru a construi
ierarhia corecta a definitiei tipurilor.
Aceasta metoda poate fi folosita pentru a incarca un assembly in mod explict, apoi sa
construiasca un obiect de un anumit tip (tip gazduit de acest assembly) si apoi sa apeleze
metodele pe acest obiect (ceva asemanator cu LoadLibrary si GetProcAddress din Win32
API) se realizeaza legarea intarziata .
Obtinerea tipurilor unui assembly (reflection method)
Exemplu
using System;
using System.Reflection;
class App
{
static void Main()
{
Assembly assem = Assembly.GetExecutingAssembly();
Reflector.ReflectOnAssembly(assem);
}
}
public class Reflector
{

Ioan Asiminoaei

13

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

public static void ReflectOnAssembly(Assembly assem)


{
WriteLine(0, "Assembly: {0}", assem);
// Find Modules
foreach (Module m in assem.GetModules())
{
WriteLine(1, "Module: {0}", m);
// Find Types
foreach (Type t in m.GetTypes())
{
WriteLine(2, "Type: {0}", t);
// Find Members
foreach (MemberInfo mi in t.GetMembers())
WriteLine(3, "{0}: {1}", mi.MemberType, mi);
}
}
}
private static void WriteLine(Int32 indent, String format,
params Object[] args)
{
Console.WriteLine(new String( , 3 * indent) + format, args);
}
}
class SomeType
{
public class InnerType {}
public Int32 SomeField = 0;
private static String goo = null;
private void SomeMethod() { }
private TimeSpan SomeProperty
{
get { return new TimeSpan(); }
set { }
}
public static event System.Threading.ThreadStart SomeEvent;
private void NoCompilerWarnings()
{
// This code is here just to make the compiler warnings go
away.
SomeEvent.ToString();
goo.ToString();
}
}

Rezultatul este:
Assembly: p7_reflection, Version=1.0.1783.28359, Culture=neutral, PublicKeyToken
=null
Module: p7_reflection.exe
Type: App
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: System.Type GetType()
Constructor: Void .ctor()
Type: Reflector
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)

Ioan Asiminoaei

14

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Method: System.String ToString()


Method: Void ReflectOnAssembly(System.Reflection.Assembly)
Method: System.Type GetType()
Constructor: Void .ctor()
Type: SomeType
Field: Int32 SomeField
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: Void add_SomeEvent(System.Threading.ThreadStart)
Method: Void remove_SomeEvent(System.Threading.ThreadStart)
Method: System.Type GetType()
Constructor: Void .ctor()
Event: System.Threading.ThreadStart SomeEvent
NestedType: SomeType+InnerType
Type: SomeType+InnerType
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: System.Type GetType()
Constructor: Void .ctor()
Press any key to continue . . .
GetExecutingAssembly = determina ce assembly contine metoda ce face apel si returneaza
o refrinta la acest obiect Assembly.
ReflectOnAssembly = afiseaza numele complet al unui assembly si apoi apeleaza
GetModules ce returneaza un vector cu elemente de tip System.Reflection.Module.
Vezi si GetTypes si GetMembers.
Obtinere assembly dintr-un AppDomain
Acelasi exemplu ca mai sus in care modificam Main dupa cum urmeaza:
static void Main()
{
foreach (Assembly assem in
AppDomain.CurrentDomain.GetAssemblies())
{
Reflector.ReflectOnAssembly(assem);
}
}

Incarcarea explicita a unui assembly


Tehnica este asemanatoare cu cea a utilizarii functiei LoadLibrary din Win32 API.
Tipul System.Reflection.Assembly ofera urmatoarele metode statice pentru a incarca un
assembly: Load, LoadFrom, si LoadWithPartialName.
Load (documentatie MS)
Loads an assembly given its AssemblyName.

Ioan Asiminoaei

15

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

[C#] public static Assembly Load(AssemblyName);


Loads the assembly with a Common Object File Format (COFF)-based image
containing an emitted assembly. The assembly is loaded into the domain of the caller.
[C#] public static Assembly Load(byte[]);
Loads an assembly given the long form of its name.
[C#] public static Assembly Load(string);
Loads an assembly given its AssemblyName. The assembly is loaded into the domain
of the caller using the supplied evidence.
[C#] public static Assembly Load(AssemblyName, Evidence);
Loads the assembly with a Common Object File Format (COFF)-based image
containing an emitted assembly.
[C#] public static Assembly Load(byte[], byte[]);
Loads an assembly given its display name, loading the assembly into the domain of
the caller using the supplied evidence.
[C#] public static Assembly Load(string, Evidence);
Loads the assembly with a Common Object File Format (COFF)-based image
containing an emitted assembly.
[C#] public static Assembly Load(byte[], byte[], Evidence);
Exemplu (MSDN)
[C#]
using System;
using System.Reflection;
class Class1
{
public static void Main()
{
Assembly SampleAssembly;
// You must supply a valid fully qualified assembly name here.
SampleAssembly = Assembly.Load("Assembly text name, Version,
Culture, PublicKeyToken");
Type[] Types = SampleAssembly.GetTypes();
// Display all the types contained in the specified assembly.
foreach (Type oType in Types)
{
Console.WriteLine(oType.Name.ToString());
}
}
}

Incarcare assembly ca fisiere de date


Metoda LoadFrom folosita in acest caz pentru a incarca un assembly furnizat ca parametru
in linia de comanda.
Presupunem ca avem doua assemblies: SomeTool.exe si Component.dll (un assembly ce
contine anumite componente pe care le foloseste SomeTool.exe si acestea sunt instalate in:
C:\SomeTool\SomeTool.exe
C:\SomeTool\Component.dll
Ioan Asiminoaei

16

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Presupunem ca mai exista un assembly cu acelasi nume, Component.dll dar situat in


radacina discului C:.
Utilizatorul va folosi SomeTools.exe pentru a incarca assembly C:\Component.dll si nu cel
din directorul curent.
C:\>C:\SomeTool\SomeTool.exe C:\Component.dll
SomeTool.exe va incarca assembly C:\Component.dll folosind metoda LoadFrom,
pasindu-i ca parametru argumentul din linia de comanda.
CLR va incarca acest assembly. Presupunem ca in metoda Main se face apel la o alta
metoda ce face referinta la un obiect din Component.dll.
Ce se va intimpla?
Va folosi CLR assembly incarcat sau va incarca assembly din directorul curent?
Deoarece assembly C:\Component.dll a fost incarcat ca un fisier , CLR nu poate sti ca
Component.dll
a
fost
incarcat,
si
ca
atare
va
incarca
assembly
C:\SomeTool\Component.dll.
Algoritmul pentru LoadFrom
La executia metodei LoadFrom, CLR deschide fisierul specificat si extrage informatii
referitaore la versiune, cultura si cheia publica din metadata fisierului, apoi intern CLR
apeleaza metoda Load, pasindu-i informatia de mai sus. Daca un asemenea assembly este
gasit, CLR compara calea completa a assembly-ului cu cea furnizata in LoadFrom si in caz
ca sunt identice, va incarca acel assembly.
Daca parametrii sunt diferiti sau daca Load nu gaseste un asemenea fisier, assembly este
considerat ca fiind fisier de date si ca atare nu constituie o parte normala a aplicatiei.
Utilizarea metodei LoadFrom este descurajata de catre documentatia MS, in principal pe
considerente de viteza de executie si pe faptul ca un assembly incarcat cu aceasta metoda
este considerat fisier de date , si deci nu face parte din AppDomain.
Construirea unei ierarhii a tipurilor derivate din Exception
Exemplul de mai jos afiseaza toate clasele ce sunt derivate in ultima instanta din
System.Exception.
Pentru a face acest lucru este necesar sa examinam tipurile din mai multe assemblies.
Aplicatia va trebui sa incarce in mod explicit toate assemblies pe care vrem sa le
scanam .
using
using
using
using
class
{

System;
System.Text;
System.Reflection;
System.Collections;
App
static void Main()
{
// Incarcam in mod explicit assembly pe care
// vrem sa aplicam reflection

Ioan Asiminoaei

17

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

LoadAssemblies(); // metoda proprie


//
//
//
//

Initializare contoare
totalTypes = numar total tipuri
totalExceptionType = numar total tipuri exceptii
exceptionTree = lista cu tipuri de exceptii

Int32 totalTypes = 0, totalExceptionTypes = 0;


ArrayList exceptionTree = new ArrayList();
// Iteram prin toate assemblies
// incarcate in acest AppDomain
foreach (Assembly a in
AppDomain.CurrentDomain.GetAssemblies())
{
// Iteram prin toate tipurile definite in acest assembly
foreach (Type t in a.GetTypes())
{
totalTypes++;
// Ignoram tipul daca nu este o clasa publica
if (!t.IsClass || !t.IsPublic) continue;
// Construim un string al ierarhiei
// de derivare a tipului.
StringBuilder typeHierarchy =
new StringBuilder(t.FullName, 5000);
// Presupunem ca tipul nu este derivat din Exception
Boolean derivedFromException = false;
// Cercetam sa vedem daca System.Exception
// este tipul de baza pentru acest tip
Type baseType = t.BaseType;
while ((baseType != null) && !derivedFromException)
{
// Adaugam tipul de baza la sfarsitul listei
typeHierarchy.Append("-" + baseType);
derivedFromException =
(baseType == typeof(System.Exception));
baseType = baseType.BaseType;
}
// Controlam urmatorul tip
if (!derivedFromException) continue;
// Am gasit un tip derivat din Exception
totalExceptionTypes++;
// Pentru acest tip derivat din Exception,
// inversam ordinea tipurilor in ierarhie
String[] h = typeHierarchy.ToString().Split(-);
Array.Reverse(h);
// Construim un nou string cu ierarhia in ordinea

Ioan Asiminoaei

18

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

// Exception -> tip derivat din Exception.


// Adaugam stringul la lista tipurilor Exception
exceptionTree.Add(String.Join("-",
1));

h,

1,

h.Length

}
}
// Sortam tipurile Exception in ordinea ierarhiei lor.
exceptionTree.Sort();
// Afisam arborescenta Exception.
foreach (String s in exceptionTree)
{
// Pentru acest tip Exception,
// separam tipul de baza sa.
String[] x = s.Split(-);
// Indentam pe baza numarului de tipuri de baza.
Console.WriteLine(
new String( , 3 * x.Length) + x[x.Length - 1]);
}
// Afisam starea finala a tipului considerat.
Console.WriteLine("\n> Of {0} types, {1} are " +
"derived from System.Exception.",
totalTypes, totalExceptionTypes);
Console.ReadLine();
}
static void LoadAssemblies()
{
String[] assemblies = {
"System, PublicKeyToken={0}",
"System.Data, PublicKeyToken={0}",
"System.Design, PublicKeyToken={1}",
"System.DirectoryServices, PublicKeyToken={1}",
"System.Drawing, PublicKeyToken={1}",
"System.Drawing.Design, PublicKeyToken={1}",
"System.EnterpriseServices, PublicKeyToken={1}",
"System.Management, PublicKeyToken={1}",
"System.Messaging, PublicKeyToken={1}",
"System.Runtime.Remoting, PublicKeyToken={0}",
"System.Security, PublicKeyToken={1}",
"System.ServiceProcess, PublicKeyToken={1}",
"System.Web, PublicKeyToken={1}",
"System.Web.RegularExpressions, PublicKeyToken={1}",
"System.Web.Services, PublicKeyToken={1}",
"System.Windows.Forms, PublicKeyToken={0}",
"System.Xml, PublicKeyToken={0}",
};
String EcmaPublicKeyToken = "b77a5c561934e089";
String MSPublicKeyToken = "b03f5f7f11d50a3a";
// Obtinem versiunea assembly ce contine System.Object.
// Vom presupune aceeasi versiune
// pentru toate celelate assemblies.

Ioan Asiminoaei

19

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Version version =
typeof(System.Object).Assembly.GetName().Version;
// Incarcam explicit assembly pe care vrem sa
// aplicam reflection
foreach (String a in assemblies)
{
String AssemblyIdentity =
String.Format(a, EcmaPublicKeyToken,
MSPublicKeyToken) +
", Culture=neutral, Version=" + version;
Assembly.Load(AssemblyIdentity);
}
}
}

Rezultatul este:
System.ApplicationException
System.Reflection.InvalidFilterCriteriaException
System.Reflection.TargetException
System.Reflection.TargetInvocationException
System.Reflection.TargetParameterCountException
System.IO.IsolatedStorage.IsolatedStorageException
System.Runtime.Remoting.MetadataServices.SUDSGeneratorException
System.Runtime.Remoting.MetadataServices.SUDSParserException
System.SystemException
System.AppDomainUnloadedException
System.ArgumentException
System.ArgumentNullException
.............................................
Of 7281 types, 135 are derived from System.Exception.
Explicatie asupra codului:
String[] assemblies = {
"System, PublicKeyToken={0}",
"System.Data, PublicKeyToken={0}",
"System.Design, PublicKeyToken={1}",
"System.DirectoryServices, PublicKeyToken={1}",
"System.Drawing, PublicKeyToken={1}",
"System.Drawing.Design, PublicKeyToken={1}",
"System.EnterpriseServices, PublicKeyToken={1}",
...

Ideea construirii acestui string, se gaseste in algoritmul folosit pentru construirea identitatii
unui assembly
foreach (String a in assemblies)
{
String AssemblyIdentity =
String.Format(a, EcmaPublicKeyToken,
MSPublicKeyToken) +
", Culture=neutral, Version=" + version;
...

altfel spus stringul assemblies contine si specificatorii de format.


Rezultatul executiei codului de mai sus este (partial) :
Ioan Asiminoaei

20

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

assemblies = System, PublicKeyToken={0}


AssemblyIdentity = System, PublicKeyToken=b77a5c561934e089, Culture=neutral,
Version=1.0.5000.0
assemblies = System.Data, PublicKeyToken={0}
AssemblyIdentity = System.Data, PublicKeyToken=b77a5c561934e089, Culture=neutral,
Version=1.0.5000.0
assemblies = System.Design, PublicKeyToken={1}
AssemblyIdentity
=
System.Design,
PublicKeyToken=b03f5f7f11d50a3a,
Culture=neutral, Version=1.0.5000.0
...
Cateva explicatii
Metoda String.Split
// string seperated by colons ';'
string info = "mark;smith;123 csharp drive;toronto;canada";
string[] arInfo = new string[4];
// define which character is seperating fields
char[] splitter = {';'};
arInfo = info.Split(splitter);
for(int x = 0; x < arInfo.Length; x++)
{
Console.WriteLine(arInfo[x] + "<br>");
}

Rezultatul este:
mark<br>
smith<br>
123 csharp drive<br>
toronto<br>
canada<br>
Descarcarea explicita a unui assembly: descarcarea unui AppDomain
CLR nu suporta abilitatea de a descarca un assembly. In loc de aceasta trebuie sa
descarcam un AppDomain ce are ca efect descarcarea tuturor assemblies din cadrul
acestuia.
Descarcarea unui AppDomain se face apeland metoda Unload, ce are drept parametru o
refrerinta la un AppDomain.
Important : Assembly care sunt incarcati intr-un AppDomain neutral nu pot fi descarcati
niciodata. Un AppDomain neutral este descarcat cand procesul se termina.
Exemplu de creare a unui AppDomain, transfer de date prin referinta in afara AppDomain.
using
using
using
class
{

System;
System.Reflection;
System.Threading;
App
static void Main()

Ioan Asiminoaei

21

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

{
// Creaza un AppDomain nou.
AppDomain ad =
AppDomain.CreateDomain("MyNewAppDomain", null, null);
// Creaza un obiect MarshalByRef in noul AppDomain
MarshalByRefType mbrt = (MarshalByRefType)
ad.CreateInstanceAndUnwrap(
Assembly.GetCallingAssembly().FullName,
"MarshalByRefType");
// Apeleaza o metoda pe acest obiect.
// Proxy redirecteaza apelul catre alt AppDomain
mbrt.SomeMethod(Thread.GetDomain().FriendlyName);
// Am terminat cu acest AppDomain.
// Il descarcam si implicit toate assemblies
// pe care le contine.
AppDomain.Unload(ad);

// Incercam sa apelam o metoda pe un alt obiect


// din AppDomain ce a fost descarcat.
// Din acest motiv se va lansa o exceptie.
try
{
mbrt.SomeMethod(Thread.GetDomain().FriendlyName);
// Urmatoarea linie nu va fi afisata.
Console.WriteLine(
"Called SomeMethod on object in other AppDomain.\n" +
"This shouldnt happen.");
}
catch (AppDomainUnloadedException)
{
// Am prins exceptia si o tratam.
Console.WriteLine(
"Fail
to
call
SomeMethod
AppDomain.\n" +
"This should happen.");

on

object

in

other

}
Console.ReadLine();
}
}
// Un tip derivat din MarshalByRefObject.
class MarshalByRefType : MarshalByRefObject
{
// Aceasta metoda de instanta poate fi apelata via proxy.
public void SomeMethod(String sourceAppDomain)
{
// Afisam numele AppDomain apelat si al AppDomain curent.
// Firul aplicatiei a facut tranzitia intre AppDomain.

Ioan Asiminoaei

22

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi

21.01.2007

Console.WriteLine(
"Code from the {0} AppDomain\n" +
"called into the {1} AppDomain.",
sourceAppDomain, Thread.GetDomain().FriendlyName);
}
}

Iesirea este:
Code from the 'p7_appdomain.exe' AppDomain
called into the 'MyNewAppDomain' AppDomain.
Fail to call SomeMethod on object in other AppDomain.
This should happen.

System.Collections Namespace
The System.Collections namespace contains interfaces and classes that define
various collections of objects, such as lists, queues, bit arrays, hashtables and
dictionaries.
Namespace hierarchy
Classes
Class
Description
ArrayList
Implements the IList interface using an
array whose size is dynamically increased
as required.
BitArray
Manages a compact array of bit values,
which are represented as Booleans, where
true indicates that the bit is on (1) and
false indicates the bit is off (0).
CaseInsensitiveComparer
Compares two objects for equivalence,
ignoring the case of strings.
CaseInsensitiveHashCodeProvider
Supplies a hash code for an object, using a
hashing algorithm that ignores the case of
strings.
CollectionBase
Provides the abstract (MustInherit in
Visual Basic) base class for a strongly
typed collection.
Comparer
Compares two objects for equivalence,
where string comparisons are casesensitive.
DictionaryBase
Provides the abstract (MustInherit in
Visual Basic) base class for a strongly
typed collection of key-and-value pairs.
Hashtable
Represents a collection of key-and-value
pairs that are organized based on the hash
code of the key.
Queue
Represents a first-in, first-out collection of
objects.
ReadOnlyCollectionBase
Provides the abstract (MustInherit in
Visual Basic) base class for a strongly
typed read-only collection.
SortedList
Represents a collection of key-and-value
pairs that are sorted by the keys and are
accessible by key and by index.

Ioan Asiminoaei

23

CLR. AppDomain. Reflection


Facultatea de Informatica Iasi Universitatea Al I. Cuza Iasi
Stack

21.01.2007

Represents a simple last-in-first-out


collection of objects.

Interfaces
Interface
ICollection
IComparer
IDictionary
IDictionaryEnumerator
IEnumerable
IEnumerator
IHashCodeProvider
IList

Description
Defines size, enumerators and
synchronization methods for all collections.
Exposes a method that compares two
objects.
Represents a collection of key-and-value
pairs.
Enumerates the elements of a dictionary.
Exposes the enumerator, which supports a
simple iteration over a collection.
Supports a simple iteration over a
collection.
Supplies a hash code for an object, using a
custom hash function.
Represents a collection of objects that can
be individually accessed by index.

Structures
Structure
DictionaryEntry

Ioan Asiminoaei

Description
Defines a dictionary key-and-value pair
that can be set or retrieved.

24