Pre nego što pređemo na Manifest, podsetio bi vas da dobro prostudirate dva prethodna posta Arhitektura Microsoft .NET Framework-a i Šta su sklopovi? Koje sve komponente sadrži .Net Framework i koji je proces kompajliranja i izvršavanja aplikacija programiranih u .Net programskim jezicima je toliko bitno znati, da ćemo prvo u najkraćim crtama ponoviti materiju koja se mora znati. Znači, Microsoft .Net Framework je platforma koja omogućava razvoj i izvršavanje .Net aplikacija. To je platforma koje obezbeđuje komponentnu infrastrukturu, integraciju programskih jezika, internet interoperabilnost, jednostavan razvoj, jednostavnu instalaciju, pouzdanost i bezbednost. CLR – Common Language Runtime je najvažniji deo Microsoft .Net Framework-a nadležan za aktiviranje objekata, izvršavanje bezbednosnih provera nad njima, njihovo smeštanje u memoriju, izvršavanje i uklanjanje iz memorije. CLR podržava sve programske jezike koje se mogu prevesti u MSIL – Microsoft Intermediate Language.
( Sklop u jednom i sklop u više fajlova )
Sledeće komponente Microsoft .Net Framework-a su BCL – Base Class Library, biblioteka baznih klasa koja se sastoji se od klasa, interfejsa i tipova podataka koje omogućavaju korišćenje funkcija sistema i FCL – Framework Class Library koja sadrži specijalizovane biblioteke tipova podataka koje sadrže Data i XML klase. Microsoft .Net Framework sadrži i klase koje omogućavaju tehnologije za razvoj aplikacija poput konzolni aplikacija, formi, WPF aplikacija, univerzalni aplikacija, mobilni aplikacija, web servisa, web aplikacija itd. Proces prevođenja izvornog koda u izvršni u najkraćim crtama se može podeliti u dva koraka. Prvo se izvorni kod prevodi u MSIL – Microsoft Intermediate Language, zatim u mašinski kod. MSIL je jezik nižeg nivoa koji se lako pretvara u mašinski kod. On omogućuje platformsku nezavisnost, poboljšanje performansi i jezičku interoperabilnost. Jednostavno klasa koja je napisana u jednom programskom jeziku može da komunicira sa klasom pisanom u drugom programskom jeziku. CTS – Common Type System – zajednički sistem tipova definiše skup pravila koje .Net kompajleri moraju da poštuju. CTS tipovi imaju istu semantiku bez obzira u kom su programskom jeziku definisani. I naravno ne treba izostaviti ni GC – Garbidge Collection – skupljač smeća, komponentu za upravljanje memorijom. GC jedino radi sa referentnim tipovima podataka, što znači da objekte na hipu do kojih ne vodi ni jedna referenca se automatski oslobađa. GC sprečava curenje memorije, tačno vreme oslobađanja memorije nije određeno i oslobađanje resursa ne treba da se radi u destruktoru klase.
Gde se sad u sve navedeno uklapa sklop?
Sklop je osnovna jedinica aplikacije .Net-a. Sklop je samoopisujuća kolekcija koda, resursa i meta podataka. Jednostavno govoreći, sklop je projekat koji se kompajlira u izvršnu datoteku *.exe ili u *.dll datoteku biblioteke. Sklop je deo vaše aplikacije, projekta ili rešenja, ne deo Microsoft .Net Framework-a. Vaša izvršna datoteka i klase koje pravite sadrže sklop. Sklop može biti javni tj. deljeni ili privatni. Deljeni sklopovi se instaliraju u poseban folder GAC - Global Assembly Cache folder; C:\Windows\Microsoft.NET\assembly\GAC_MSIL i mogu ih koristiti i druge aplikacije dok privatni sklop se nalazi u direktorijumu aplikacije. Samo da napomenem da su se pre verzije Microsoft .Net Framework-a 4.0, GAC folder nalazio u C:\Windows\assembly i da ga još uvek koriste starije aplikacije. Tek kad pogledate strukturu sklopa dolazimo do Manifest sklopa ili skraćeno rečeno Manifest. Bez obzira koliko imate datoteka sklopova u jednoj datoteci se uvek moraju nalaziti Manifest sklopa. Manifest sklopa nije isto što i meta podaci iako programeri imaju takav utisak.
Šta je Manifest?
Sklop se sastoji od meta podataka sklopa koji opisuju celi sklop, meta podataka tipa koji opisuju izvezene tipove i metode, MSIL koda i resursa. Meta podaci opisuju sadržaj sklopa dok Manifest opisuje sam sklop. Znači, sklop sadrži Manifest, dok Manifest sadrži meta podatke plus dodatne tabele. Meta podaci opisuju sami sebe, dok Manifest uključuje i reference vanjskih klasa, zavisnosti od drugih sklopova i informacije (tabele) o meta podacima. Meta podaci se nalaze u sklopovima i modulima dok je Manifest uvek prikazan u sklopovima. Manifest nije ništa već ekstra tabela u selekciji meta podataka PE – Portable Executable fajla koji sadrži:
- Assembly Name – ime sklopa, tekst tipa string koji sadrži ime sklopa
- Version Number – verzija sklopa
- Culture – informacije o kulturi ili jeziku koje sklop podržava. Ukoliko sklop sadrži informacije o kulturi, takav sklop se smatra satellite assembly – satelitski sklop
- Strong Name – strogo ime, javni ključ proizvođača ukoliko je definisano strogo ime
- Lista svih fajlova u sklopu – svi fajlovi koji čine sklop uključujući i fajl koji sadrži manifest moraju biti u istom direktorijumu
- Type reference information – informacije o referentnim tipovima koji će se izvoziti iz sklopa
- Lista referencirani sklopova – informacije o drugim sklopovima koji statički referenciraju sklop
( Struktura Manifest-a )
Kako možemo videti manifest u praktičnom primeru?
Napravićemo jednostavnu konzolnu aplikaciju koja nam ukazuje da se radi o privatnom sklopu. Nazvaćemo je MyManifest, unesite sledeći kod:
using System;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyManifest
{
class Program
{
static void Main(string[] args)
{
WriteLine("This is a private
assembly!");
WriteLine(Environment.NewLine + "Press any key to
continue...");
ReadKey();
}
}
}
This is a private assembly!
Press any key to continue...
U Solution Explorer kliknite desnim tasterom miša na projekat MyManifest i u meniju kliknite na Properties. Ukoliko vam je selektovan Application tab, kliknite na dugme Assembly information. Kad vam se otvori forma za unos informacija o sklopu, unesite ili promenite neke informacije, na primer unesite vaše ime kompanije i kopirajta.
( Assembly Information forma desno )
Potvrdite vaš unos pritiskom levog tastera miša na dugme OK i vratite se na Solution Explorer. U Solution Explorer pronađite datoteku AssemblyInfo.cs i kliknite na datoteku levim tasterom miša. Videćete da su se informacije u datoteci takođe promenile. Vi možete i direktno u navedenom fajlu da menjate informacije o vašem sklopu.
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly
is controlled through the following
// set of attributes. Change these
attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MyManifest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Manuel
Corporation")]
[assembly: AssemblyProduct("MyManifest")]
[assembly: AssemblyCopyright("Manuel Corporation
Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the
types in this assembly not visible
// to COM components. If you need to access a type in this assembly
from
// COM, set the ComVisible attribute to
true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of
the typelib if this project is exposed to COM
[assembly: Guid("3dc9d0d8-f278-4cfb-8345-300d80e42718")]
// Version information for an assembly
consists of the following four values:
//
//
Major Version
//
Minor Version
//
Build Number
//
Revision
//
// You can specify all the values or you
can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: NeutralResourcesLanguage("en-US")]
( Properties - Details datoteke MyManifest.exe )
Zatvorite Windows Explorer ili File Explorer i otvorite Developer Command Prompt. U zavisnosti od direktorijuma gde ste usnimili vašu aplikaciju, otkucajte u konzoli sledeće komande:
C:\Program Files (x86)\Microsoft Visual Studio 14.0>cd..
C:\Program Files (x86)>cd..
C:\>cd workspace
C:\Workspace>cd c#
C:\Workspace\c#>cd mymanifest
C:\Workspace\c#\MyManifest>cd mymanifest
C:\Workspace\c#\MyManifest\MyManifest>cd bin
C:\Workspace\c#\MyManifest\MyManifest\bin>cd release
C:\Workspace\c#\MyManifest\MyManifest\bin\Release>ildasm mymanifest.exe
Kad kliknete Enter otvoriće vam se fajl mymanifest.exe u ILDASM alatu. Kliknite na Manifest vašeg sklopa.
( Pregled Manifest-a sklopa alatom ILDASM )
Pogledajte meta podatke vašeg sklopa i pod Manifestom ćete videti informacije koje ste promenili.
// Metadata version:
v4.0.30319
.assembly extern
mscorlib
{
.publickeytoken =
(B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly MyManifest
{
.custom instance void
[mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32)
= ( 01 00 08 00 00 00 00 00 )
.custom instance void
[mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor()
= ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65
70 74 69 6F 6E 54 68 72 6F 77 73 01 )
// ceptionThrows.
// --- The following custom attribute is
added automatically, do not uncomment -------
//
.custom instance void
[mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype
[mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02
00 00 00 00 00 )
.custom instance void
[mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0A
4D 79 4D 61 6E 69 66 65 73 74 00 00 )
// ...MyManifest..
.custom instance void
[mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01
00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string)
= ( 01 00 00 00 00 )
.custom instance void
[mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00
12 4D 61 6E 75 65 6C 20 43 6F 72 70 6F 72
// ...Manuel Corpor
61
74 69 6F 6E 00 00 )
// ation..
.custom instance void
[mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00
0A 4D 79 4D 61 6E 69 66 65 73 74 00 00 )
// ...MyManifest..
.custom instance void
[mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00
25 4D 61 6E 75 65 6C 20 43 6F 72 70 6F 72
// ..%Manuel Corpor
61
74 69 6F 6E 20 43 6F 70 79 72 69 67 68 74 20
// ation Copyright
C2 A9 20 20 32 30 31 36 00 00 ) // .. 2016..
.custom instance void
[mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00
00 00 00 )
.custom instance void
[mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = (
01 00 00 00 00 )
.custom instance void
[mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00
24 33 64 63 39 64 30 64 38 2D 66 32 37 38
// ..$3dc9d0d8-f278
2D
34 63 66 62 2D 38 33 34 35 2D 33 30 30 64 38
// -4cfb-8345-300d8
30 65 34 32 37 31 38 00 00 ) // 0e42718..
.custom instance void
[mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01
00 07 31 2E 30 2E 30 2E 30 00 00 )
// ...1.0.0.0..
.custom instance void
[mscorlib]System.Resources.NeutralResourcesLanguageAttribute::.ctor(string) = (
01 00 05 65 6E 2D 55 53 00 00 ) // ...en-US..
.custom instance void
[mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = (
01 00 1A 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework
2C 56 65 72 73 69 6F 6E 3D
76 34 2E 36 01 00 54 //
,Version=v4.6..T
0E 14 46
72 61 6D 65 77 6F 72 6B 44 69 73 70 6C
// ..FrameworkDispl
61 79 4E 61 6D 65 12 2E 4E 45 54 20 46 72 61 6D // ayName..NET Fram
65 77 6F 72 6B 20 34 2E 36 ) // ework 4.6
.hash algorithm
0x00008004
.ver 1:0:0:0
}
.module MyManifest.exe
// MVID: {C9685E8E-7AEF-4CCB-8A68-F52C6FF9F247}
.imagebase
0x00400000
.file alignment
0x00000200
.stackreserve
0x00100000
.subsystem
0x0003 // WINDOWS_CUI
.corflags
0x00020003 // ILONLY 32BITPREFERRED
// Image base:
0x024F0000
Vi možete navedene informacije zabeležiti i
u posebnu tekstualnu datoteku sledećom naredbom:
ildasm /out:mymanifest.txt mymanifest.exe
Kako sve to izgleda možete pogledati i na video-u:
( C# 6.0 Tutorial - Advanced - 3. Manifest )
Kako da registrujem sklop u GAC – Global Assembly Cashe?
Najbolje da to vidite praktičnim primerom. Prvo ćemo napraviti jedan javni ili deljeni sklop. Znači pokrenite novi projekat, ali ovaj put umesto konzolne aplikacije izaberite šablon Class Library i vašu deljenu datoteku nazovite ClassLibrary, zatim unesite sledeći kod.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ClassLibrary
{
public class TestClass
{
public static string TestMethod => "This is a public or
shared assembly.";
}
}
( Create Strong Name Key forma )
Potvrdite vaš unos, kompajlirajte vaš projekat kao Release i dobićete poruku koja vas obaveštava da vi ne možete direktno pokrenuti vašu datoteku što je očigledno, ali će vaša datoteka biti kompajlirana. Zatvorite vaš projekat. Generisanje vašeg ključa za strong ime ste mogli da uradite i jednostavnije preko alata SN.EXE – strong name; koristeći konzolu sledećom komandom:
sn -k TestKey.snk
Kad ste strong imenovali vaš sklop vi možete samo da referencirate sklopove koji su takođe strong imenovani iz sigurnosnih razloga. Međutim tada možete imati drugi problem. Neko od zaposlenih može kopirati vaš privatni ključ i zato se ključ ne pravi sve do samog puštanja aplikacije u prodaju. Vaš čvrsto imenovani sklop takođe ne garantuje da njegov ključ dolazi od vas. On samo pokazuje da osoba koja je kreirala sklop ima privatni ključ. Zato kompanije koje prave softver koriste Microsoft Authenticode Certificate koji kupe online i plaćaju njegovu validaciju na godišnjem nivou. Otvorite Windows Explorer ili File Explorer, potražite direktorijum ClassLibrary koji ste prethodno napravili. Kad otvorite TestKey fajl u tekst editoru, videćete da je vaš ključ kriptovan sa Microsoft Strong Cryptographic Provider-om. Sad kad imate definisan strong ime za vaš sklop, onda ga možete generisati u GAC - Global Assembly Cache pomoću alata GACUTIL.EXE. S obzirom da su nam potrebna administratorska ovlašćenja Windows operativnog sistema, neophodno je da otvorite Developer Command Prompt kao administrator, tako što će te kliknuti desnim tasterom miša na isti i pokrenuti ga izborom u meniju Run as Administrator. U zavisnosti gde ste usnimili vaš projekat unesite sledeće komande:
C:\WINDOWS\system32>cd..
C:\Windows>cd..
C:\>cd workspace
C:\Workspace>cd c#
C:\Workspace\c#>cd classlibrary
C:\Workspace\c#\ClassLibrary>cd classlibrary
C:\Workspace\c#\ClassLibrary\ClassLibrary>cd bin
C:\Workspace\c#\ClassLibrary\ClassLibrary\bin>cd release
C:\Workspace\c#\ClassLibrary\ClassLibrary\bin\Release>gacutil.exe -i classlibrary.dll
Microsoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.0
Copyright (c) Microsoft Corporation. All rights reserved.
Assembly successfully added to the cache
C:\Workspace\c#\ClassLibrary\ClassLibrary\bin\Release>
Ukoliko otvorite Windows Explorer ili File Explorer i pogledate direktorijum C:\Windows\Microsoft.NET\assembly\GAC_MSIL\ videćete novi direktorijum C:\Windows\Microsoft.NET\assembly\GAC_MSIL\ClassLibrary\v4.0_1.0.0.0__8c7b556ffba01917 gde je kopirana vaša deljena datoteka classlibrary.dll koju mogu sad da koriste i drugi projekti bez obzira koji .Net programski jezik koristite.
( GAC - Global Assembly Cashe folder )
Jednostavno referencirate datoteku i ona će se iskopirati u vaš projekat. Da bi proverili kako naša navedena datoteka radi, pokrenite nov projekat; konzolnu aplikaciju i nazovite je Gac. Otvorite Solution Explorer i kliknite desnim tasterom miša na direktorijum References, zatim kliknite na Add Reference i preko Reference Manager-a referencirajte classlibrary.dll.
( Reference Manager forma )
Zatim unesite u Main proceduru vaše aplikacije sledeći kod:
using System;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Gac
{
class Program
{
static void Main(string[] args)
{
string test = ClassLibrary.TestClass.TestMethod;
WriteLine(test);
WriteLine(Environment.NewLine + "Press any key to
continue...");
ReadKey();
}
}
}
This is a public or shared assembly.
Press any key to continue...
Kako sve to izgleda možete pogledati i na video-u:
( C# 6.0 Tutorial - Advanced - 4. Register an assembly in GAC )
Šta su resursi i sklopovi resursa?
Resursi su vam podaci koji se ne mogu izvršavati iako postoje u vašoj aplikaciji. To može biti skup slika ili stringovi prikazani na korisničkom interfejsu poput kulture za posmatrani računar. Smeštanjem podataka u resursne datoteke vi zapravo možete da menjate podatke koje program zahteva, a da pri tome ne morate ponovo da kompajlirate celu aplikaciju. Pre su programeri uglavnom koristili posebnu alatku za pravljenje resursnih datoteka, ResEditor. Sad jednostavno možete dodate vašem projektu šablon Resorce File kao što dodajete i bilo koji drugi šablon u Visual Studio-u i napraviti vlastite resurse za vašu aplikaciju. Poenta je da sklopovi mogu obuhvatati i resursne fajlove. Resursnim fajlovima ćemo se baviti kad za tim imamo potrebu, kao na primer kad vam je potrebno da vaša aplikacija ima ikonicu aplikacije koju vi želite da ima i kad budemo opisali postove kako se podaci čuvaju u datotekama iako nisu baze podataka.
Šta je refleksija?
Refleksija je opšti pojam koji obuhvata razne bazne .Net klase i koji nam omogućavaju da saznamo informacije o tipovima podataka u aplikacijama i drugim sklopovima kao i da pročitamo druge meta podatke iz manifest sklopa. Većina ovih klasa se nalazi u prostoru imena System.Reflection. Pogledajte kod sledećeg programa koji će vam biti jako koristan da očitate polja, konstruktore, propertije i metode bilo kojeg tipa podataka, čak i one koje vi napravite. Pokrenite novu konzolnu aplikaciju i nazovite je Reflection. Unesite sledeći kod, ali obratite pažnju da uvedete imenski prostor System.Reflection.
using System;
using static System.Console;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
try
{
string typeName = String.Empty;
Write("Enter type name:
");
typeName = ReadLine();
Type T = Type.GetType(typeName);
FieldInfo[] fields = T.GetFields();
WriteLine(Environment.NewLine + "Fields:" + Environment.NewLine);
foreach (FieldInfo
item in fields)
{
WriteLine(item.ReflectedType.Name + " " + item.Name);
}
PropertyInfo[] properties =
T.GetProperties();
WriteLine(Environment.NewLine + "Properties:" + Environment.NewLine);
foreach (PropertyInfo
item in properties)
{
WriteLine(item.ReflectedType.Name + " " + item.Name);
}
ConstructorInfo[] constructors =
T.GetConstructors();
WriteLine(Environment.NewLine + "Constructors:" + Environment.NewLine);
foreach (ConstructorInfo
item in constructors)
{
WriteLine(item.ReflectedType.Name + " " + item.Name);
}
MethodInfo[] methods = T.GetMethods();
WriteLine(Environment.NewLine + "Methods:" + Environment.NewLine);
foreach (MethodInfo item in methods)
{
WriteLine(item.ReflectedType.Name + " " + item.Name);
}
}
catch
(Exception ex)
{
WriteLine(Environment.NewLine + ex.Message);
}
WriteLine(Environment.NewLine + "Press any key to
continue...");
ReadKey();
}
}
}
Enter type name: System.String
Fields:
String Empty
Properties:
String Chars
String Length
Constructors:
String .ctor
String .ctor
String .ctor
String .ctor
String .ctor
String .ctor
String .ctor
String .ctor
Methods:
String Join
String Join
String Join
String Join
String Join
String Equals
String Equals
String Equals
String Equals
String Equals
String op_Equality
String op_Inequality
String get_Chars
String CopyTo
String ToCharArray
String ToCharArray
String IsNullOrEmpty
String IsNullOrWhiteSpace
String GetHashCode
String get_Length
String Split
String Split
String Split
String Split
String Split
String Split
String Substring
String Substring
String Trim
String TrimStart
String TrimEnd
String IsNormalized
String IsNormalized
String Normalize
String Normalize
String Compare
String Compare
String Compare
String Compare
String Compare
String Compare
String Compare
String Compare
String Compare
String Compare
String CompareTo
String CompareTo
String CompareOrdinal
String CompareOrdinal
String Contains
String EndsWith
String EndsWith
String EndsWith
String IndexOf
String IndexOf
String IndexOf
String IndexOfAny
String IndexOfAny
String IndexOfAny
String IndexOf
String IndexOf
String IndexOf
String IndexOf
String IndexOf
String IndexOf
String LastIndexOf
String LastIndexOf
String LastIndexOf
String LastIndexOfAny
String LastIndexOfAny
String LastIndexOfAny
String LastIndexOf
String LastIndexOf
String LastIndexOf
String LastIndexOf
String LastIndexOf
String LastIndexOf
String PadLeft
String PadLeft
String PadRight
String PadRight
String StartsWith
String StartsWith
String StartsWith
String ToLower
String ToLower
String ToLowerInvariant
String ToUpper
String ToUpper
String ToUpperInvariant
String ToString
String ToString
String Clone
String Trim
String Insert
String Replace
String Replace
String Remove
String Remove
String Format
String Format
String Format
String Format
String Format
String Format
String Format
String Format
String Copy
String Concat
String Concat
String Concat
String Concat
String Concat
String Concat
String Concat
String Concat
String Concat
String Concat
String Concat
String Intern
String IsInterned
String GetTypeCode
String GetEnumerator
String GetType
Press any key to continue...
Jednostavno možete videti sva polja, konstruktore, propertije i metode tipa System.String. Kako navedeni program izgleda možete pogledati i na video-u:
( C# 6.0 Tutorial - Advanced - 5. Reflection )
No comments:
Post a Comment