A .NET technológia lehetővé teszi alkalmazások, programok, szolgáltatások nyelv-, rendszer- és platformfüggetlen felépítését. A nyelvfüggetlenség nemcsak azt jelenti, hogy az alkalmazást bármely .NET nyelven megírhatjuk, hanem azt is, hogy az alkalmazásunk moduljait különböző .NET nyelveken tudjuk megírni, majd ezeket a modulokat könnyen összekapcsolhatjuk egy alkalmazássá.
A .NET vázlatos felépítése
Az alábbi elvek betartásával sok fejfájást előzhetünk meg:
A VB6-ban minden osztálynak lehetett alapértelmezett tulajdonsága.
Pl. a TextBox esetében a Text az alapértelmezett tulajdonság.
Legyen két TextBox típusú objektumunk:
Ekkor az a = b utasítással a b alapértelmezett tulajdonságát (Text) értékül adja az a
alapértelmezett tulajdonságának
Ha azt szeretnénk, hogy az a egy referencia legyen b-re,
akkor a következőt kell írni: Set a = b
A VB.NET-ben megszüntették az alapértelmezett tulajdonságot.
Az a = b utasítás itt azt jelenti, hogy az
a legyen a b egy referenciája.
Ha a b Text tulajdonságát szeretnénk az a Text tulajdonságának értékéül adni, akkor az
a.Text = b.Text utasítást kell írnunk
(mint egy tetszőleges publikus tulajdonság esetében). Ugyanakkor megmaradt a default property némiképpen
változtatott viselkedéssel. Ha van valamilyen belső adatrendszerünk, amelynek elemeit indexekkel lehet
egyértelműen azonosítani, akkor használhatjuk. Pl. ha van az osztályunkon belül egy tömb, amiben belső adatokat
tárolunk, akkor egy default property-vel elérhetjük, hogy az objektum nevével, és egy indexszel, ennek a tömbnek
az elemére hivatkozhassunk. Mivel a property továbbra is a get és set parancsokat hajtja végre, nemcsak számokat
adhatunk meg, és nem csak tömböket használhatunk, hanem bármilyen adatszerkezetet, amiben az index alapján
azonosíthatunk egy elemet. Az index lehet String is. A set és get procedúráiban pedig magunk valósíthatjuk meg
az indexhez az elemek hozzárendelését.
Példa:
Ekkor megengedett az értékadás és hivatkozás ilyen formája:
Az eljárás- és függvényhívásnál mindig ki kell tenni a zárójelet:
A VB6-ban helyes volt az alábbi eljáráshívas:
A VB.NET-ben az alábbi módon helyes:
Tehát a .NET-ben mindig kell zárójel, akkor is, ha nincs visszatérési érték. A call kulcsszó megmaradt, de nincs különösebb jelentősége.
A static kulcsszó nem kerülhet alprogram neve elé:
Az alábbi kód VB6-ban azt jelentette, hogy az alprogram változói statikusak.
VB.NET-ben az alábbi módon tudjuk megírni:
A RETURN kulcsszó:
A Return kulcsszónál egy alprogram rögtön visszatér az őt hívó alprogramhoz. Függvények esetében a visszatérési értéket is át lehet vele adni.
Egy függvényből való visszatérés VB6-ban:
Egy függvényből való visszatérés VB.NET-ben:
A legfőbb változás, hogy a VB.NET teljesíti az objektum orientált fejlesztőrendszer mind a négy szükséges feltételét:
VB.NET–ben minden változó objektum, még egy egyszerű egész is. Minden objektum a System.Object nevű alapobjektumból származik, örökölve ennek alaptulajdonságait (metódusait stb.). Így például — bár minden objektumnak kell legyen létrehozó (constructor), illetve felszabadító (destructor) metódusa — ezeket nem szükséges megírni saját objektumainkhoz, ha megelégszünk a System.Object alapmetódusaival.
Egyéb újdonságok:
A megszűnt elemek után a teendők olvashatók.
A VB.NET-ben konstruktor váltja az osztályok Initialize eseményét. A működése lényegében azonos, egy fontos kivétellel, hogy a konstruktort nem lehet explicit hívni, és így biztosan csak egyszer fut le. A konstruktor deklarációja Sub New... A program default konstruktort csak akkor hoz létre, ha mi nem hoztunk létre sajátot.
Természetesen a konstruktor is paraméterezhetők és túlterhelhetők.
Alapértelmezésben a konstruktorok nem öröklődnek Visual Basicben. Ha az utódosztály konstruktorából meghívjuk az ősosztály konstruktorát, akkor azt még az első sorban kell megtenni. Finalize metódus (destruktor) automatikusan hívódik meg, ha egy objektum elhagyja hatókörét vagy Nothing-ra állítjuk. Ezzel kikényszeríthetjük, hogy a hulladékgyűjtő a következő alkalommal eltávolítsa az objektumot a memóriából. Finalize metódusnál használnunk kell az Overrides kulcsszót, mert tulajdonképpen az Object osztályba beépített Finalize metódust írjuk felül, mivel minden osztály, még ha nem is jelöltük, ennek az Object nevezetű ősosztálynak a leszármazottja.
Egy másik lehetőség az Objektum eltávolítására, ha implementáljuk az IDisposable interface-t ami után a Dispose utasítás segítségével, mikor a felhasználó végzett az objektummal, felszabadíthatjuk az általa foglalt erőforrásokat. Fontos megjegyezni, hogy abban az esetben, ha ezen hívás elmarad, akkor az objektumunk a végtelenségig a memóriában marad - szemét-gyűjtő nem foglalkozik többet vele
Visual Basic lehetőséget ad arra is, hogy a két technikát keverjük. Ha a felhasználónak eszébe jut a munka végezetével
meghívni a Dispose-t, akkor ezzel informáljuk a szemét-gyűjtőt hogy végezze el a feladatát (GC.SuppressFinalize()).
Ha elfelejtjük meghívni a Dispose függvényt, de a szemét-gyűjtő úgy véli, hogy befejeztük az objektum használatát, fel tudja szabadítani a tárhelyet
Ha szükségünk van arra, hogy egy értéktípusú változót referenciatípusúként tudjunk kezelni, akkor használhatjuk a bedobozolást.
Ez a funkció akkor is működik ha az Option Strict on-ra van állítva, sőt vannak esetek amikor a háttérben ez történik annak ellenére, hogy mi nem mondjuk meg konkrétan, hogy ezt szeretnénk.
Itt bedobozolódik, és az Object osztály ToString függvénye hívódik meg.
Visszaalakításnál a TypeOf-fal megnézhetjük, hogy az adott típusra visszaalakítható-e, és a DirectCast-tal pedig visszaalakíthatjuk az objektumot.
A névterek segítségével logikailag szétválaszthatjuk a programunkat. Egy névtéren belül alnévteret is definiálhatunk. Vannak beépített névterek pl. a System, de sajátot is létrehozhatunk, az alábbi módon:
Ha sokszor kell használnunk egy névtér objektumait és nem szeretnénk mindig kiírni a minősítést, akkor az Imports névtérnév utasítás kiadása után minősítés nélkül hivatkozhatunk a névtér objektumaira. Pl.: Az Imports System.WinForms kiadása után a Dim x As System.WinForms.Button helyett elég a Dim x as Button utasítást írni.
A VB6-ban csak interfész öröklődésre volt lehetőség, de a VB.NET-ben már osztályokból is származtathatunk gyerekosztályokat. Egy osztályt származtatni az Inherits kulcsszóval tudunk pl.:
Ha azt szeretnénk, hogy az osztályunkból már ne lehessen tovább származtatni, akkor azt az alábbi módon kell definiálni:
Ha pedig absztrakt osztályt szeretnénk definiálni, akkor ezt a következő módon tehetjük meg:
Ilyenkor a Dim p As New Person hibát okoz.
Egy osztály metódusai és tulajdonságai felüldefiniálhatóak is lehetnek. Ekkor a szülő osztályban Overridable kulcsszóval kell definiálnunk őket, a gyerek osztályban pedig az Overrides kulcsszóval mondjuk meg a fordítónak, hogy felüldefiniálásról van szó. Egy osztálynak lehetnek absztrakt metódusai is, ezeket a MustOverride kulcsszóval vezetjük be. A NotOverridable kulcsszóval jelezzük, ha egy metódust nem lehet felülírni. Ha ennek ellenére mégis felül szeretnénk írni egy metódust, akkor azt elfedhetjük a Shadows kulcsszóval. Azonban ez nem a fenti metódus leszármazottja lesz, hanem egy új metódus. Ha az adott objektum metódusát meghívjuk, akkor az újonnan létrehozott metódus fog lefutni, viszont ha a polimorfizmust használjuk, akkor a régi. Erre láthatunk példát a példaprogramoknál Shadows-zal való elfedés címen.
Ha osztályszintű változókat, függvényeket vagy procedúrákat szeretnénk létrehozni, azt a Shared kulcsszóval tehetjük meg.
A Me kulcsszóval a metódustörzsekben az adott példányra hivatkozhatunk vele. Más nyelvekben a this, vagy self kulcsszóval egyezik meg.
Az utódosztályban felülírt metódusokban az ősosztályban levő eredeti metódusokat a MyBase kulcsszó segítségével érhetjük el.
A MyClass kulcsszóval felülírható metódusokat hívhatunk meg az osztályunkban, miközben biztosítjuk, hogy a metódus felülírt változata helyett a metódusnak az osztálybeli megvalósítása hívódjék meg.
A .NET keretrendszer és így a Visual Basic .NET is támogatja a szálakat. A System.Threading névtér tartalmaz több különböző eszközt a többszálú alkalmazásokhoz. A Thread osztály természetesen az alap osztály, ami reprezentálja a szálakat. Egy Visual Basic kliens programnak automatikusan egy szál hoz létre a CLR és az operációs rendszer, ezt hívjuk fő szálnak. Többszálú programot további szálak létrehozásával készíthetünk. A Thread osztály alapvetően az System.Object-ből származik, tehát az Equals,Finalize,GetType metódusai használhatók. Egy szál létrehozása a következőképpen történik, először importáljuk a System.Threading csomagot:
Ugyan ezt még nem nevezhetjük tényleges párhuzamos programozásnak, ennek ellenére fontos, hogy elmélyüljünk a .NET Delegate-jeiben.
A .NET delegate típus lényegében egy típus-helyes, objektum-orientált, függvény mutató. Amikor deklarálunk egy
delegate-t akkor szükségünk lesz - amit a fordító legenerál nekünk - egy NotInheritable osztályra a System.MulticastDelegate-ból származtatva.
A BinaryOp bármilyen metódusra rá tud mutatni ami két számot vár, és számot is ad vissza.
A következő osztályt generálja dinamikusan a fordító a delegate-ből:
Ezek után már csak rá kell mutatnunk az típus-helyes függvényre, majd az Invoke paranccsal szinkron hívást kezdeményezhetünk:
Az eredmény futtatás után:
A delegate megismerése után, már igen egyszerű dolgunk van.
A BinaryOp osztályunk rendelkezett két eddig nem használt függvénnyel: BeginInvoke, EndInvoke
BeginInvoke-nak átadjuk először a két Integer típusunkat, majd az utolsó két paraméterünk egy System.AsyncCallback
és egy System.Object.
Most mindkettőnek Nothing-ot adunk, és az EndInvoke-ra koncentrálunk, aminek a visszatérési értéke Integer típus.
Lehetőségünk van felparaméterezni a BeginInvoke funkciót, egy AsyncCallback metódussal. Ebben az esetben a munka végeztével ez hívódik meg:
A .NET keretrendszerből kapott névtér használata tökéletesen analóg minden támogatott programnyelvben, de azért, hogy lássunk a tényleges implementációt, egy példán prezentáljuk működését:
A munkás osztályunk:
Maga a hívás:
Egy jó angol leírás MySQL Connector/NET letöltés
A WCF a .NET Framework 3.0-ban jelent meg először.
A WCF segítségével szolgáltatás orientált alkalmazásokat tudunk létrehozni, amelyekkel akár más platformon futó alkalmazásokkal is kommunikálhatunk.
Akár Linuxon futó alkalmazásokkal is hatékonyan tud együttműködni.
Tehát a WCF nem más, mint egy új generációs technológia elosztott alkalmazások fejlesztéséhez.
A WCF egy egységes programozási modellt nyújt a fejlesztők számára.
Így ugyanabban a környezetben tudunk fejleszteni, ha webszolgáltatást, enterprise webszolgáltatást vagy épp .NET Remoting alkalmazásokat írunk.
Így egy technológia ismeretével a korábbinál kevesebbet kell kódolnunk és hatékonyabban tudunk elosztott alkalmazásokat készíteni.
Alapvetően SOA (Service Oriented Architecture) szemléletet követ a WCF, de a SOA -nál többet nyújt.
Akár bináris kommunikációra, nyers XML kommunikációra, illetve a P2P kommunikációra is képes.
A WCF terminológiában két szereplőről beszélhetünk.
Van a szolgáltatás (egy- vagy több végpontot publikál) és van a kliens, amely a szolgáltatások végpontjainak üzeneteket tud küldeni,
és a szolgáltatás végpontoktól üzeneteket tud kapni.
Minden végpont 3 dolgot fog össze. Az ABC-t. Azaz az Address-t, a Binding-ot , Contract-ot.
De mik is ezek?
Az Address a végpont címe. Ez tulajdonképpen egy URL, amelynek segítségével elérjük az adott szolgáltatást.
A Binding definiálja, hogy milyen módon történik a kommunikáció. (TCP/IP, HTTP stb.. ) Számos előre definiált Bindingot nyújt számunkra a WCF.
A Contract a szolgáltatás interfacenek a leírása, azt határozza meg, hogy az adott szolgáltatás milyen műveleteket támogat.
Ez definiálható .NET interfacek formájában vagy WSDL nyelvű leírással is.
Azonban mivel átjárás lehetséges a két megoldás között ezért ez lényegtelen számunkra.
A WCF számos beépített kötés típussal rendelkezik, amelyek a legkülönfélébb transzport protokollokat, titkosítást és biztonsági előírásokat valósítanak meg. A leggyakrabban használatos kötések a következők:
A WCF szerződések meghatározzák az adott szolgáltatás viselkedését. A WCF ötféle szerződést ismer.
Service Contract
Minden WCF osztály implementál legalább egy Service Contractot, amely a szolgáltatás által publikált műveleteket definiálja.
A Service Contract egy olyan interface, vagy osztály, amely a [ServiceContract] attribútummal van ellátva.
Operation Contract
A műveletszerződés a szolgáltatás által definiált műveleteket definiálja.
Műveletszerződés olyan metódus, amely el van látva egy [OperationContract] attribútummal az inteface-en vagy az osztályon belül.
Metaadatcsere
Ha kész a szolgáltatásunk ezt el kell érnünk a kliensből, de ehhez meg kell kapnia a szerződés leírását.
De, hogy kapja meg a szerződés kódját a kliens? Erre több lehetőség is van.
1) Vagy Copy –Paste-tel beilleszthetjük és meghívjuk. Ez egyszerű, de sok esetben lehetetlen feladat hisz mi van akkor ha a szolgáltatás Java platformon fut? Akkor hiába kapnánk meg az interfacet.
2) SOA környezetben természetesen van erre megoldás.
2.1) MetaDataExchange - metaadatcsere cégpont. Egy adott címen letölthetővé válnak a szolgáltatás megvalósításának elemei. Visual Studio 2008-ból az Add Service Reference szolgáltatással használható
2.2) Illetve, ha fejlesztőcsapat másik részét megkérjük, hogy küldje el a számunkra az adott szolgáltatás WSDL vagy XSD leírását.
De hogy publikáljuk a szolgáltatásunkat? Tulajdonképpen erre sok megoldás létezik. Lehet akár egy console alkalmazás, egy windows forms, egy Windows Service, vagy egy WPF alkalmazás is ami hosztolja. Vagy akár az IIS is hosztolhatja számunkra a szolgáltatást (IIS 5.1, IIS 6.0). Viszont az IIS 5.1 és 6.0 használatával van néhány megkötés a hostolással kapcsolatban. Csak HTTP vagy HTTPS alapú kommunikációt lehet megvalósítani, így csak olyan bindingot használhatunk, ami ezt a kommunikációt valósítja meg. IIS 7.0 alatt már nincsenek ezek a megkötések ott már lehet használni TCP-t vagy bármely más kommunikációt.
Ahhoz, hogy WCF-et használni tudjuk szükségünk lesz a System.ServiceModel névtérre.
Technikai követelmények:
Operációs Rendszer: Windows Vista, Windows XP SP2 vagy Windows Server 2003 SP1
IDE: Visual Studio 2008 vagy Visual Studio 2005 SP1 with WCF extension
Framework: .NET 3.0 , .NET 3.5
SDK: Microsoft Windows Software Development Kit 6.0
Természetesen minden szoftver INGYENESEN és LEGÁLISAN letölthető az egyetem MSDNAA oldaláról.
Mielőtt nekikezdenénk a feladatnak, szükségünk lesz néhány szoftverre. Ahhoz, hogy a Windows Communication Foundation –t használjuk a következőket kell feltelepíteni.
A feladatunk annyi lesz, hogy egy olyan kliens és szerveralkalmazást fogunk elkészíteni, amelynél a szerver egy személyi nyilvántartó adatbázis adatait lista, valamint listaelem formájában küldi a kliensnek. Ezt a kliens fogadja, és egyszerű módon kiírja a képernyőre. Így lesz egy olyan alkalmazásunk, melynek segítségével bárhonnan távolról felügyelhetjük, személyi nyilvántartásunk adatait.
Legelőször a szerveroldali programot fogjuk elkészíteni:
A szerveralkalmazás fogja az adatokat lekérdezni, és majd ha a kliensnek szüksége van ezekre az adatokra akkor el fogja neki küldeni.
Indítsuk el a Visual Studio 2008-at rendszergazdai módban, majd a válasszuk ki a File -> New -> Project… menüpontot és a megjelenő ablakban válasszuk ki a templatek közül a Class Library–t.
A neve legyen például: Wcf.Server, majd kattintsunk az OK gombra.
Ahhoz, hogy használni tudjuk a WCF-et szükségünk lesz a System.ServiceModel névtérre.
Ehhez kattintsunk jobb egérgombbal a Solution Explorerben a References-re és válasszuk ki a megjelenő helyi menüből az Add Reference menüpontot.
A megjelenő ablakban a .NET fül alatt keressük ki a System.ServiceModel –t majd jelöljük ki és kattintsunk az OK gombra.
ezzel megvagyunk, adjunk a Solution -ünkhöz egy osztályt.
Kattintsunk jobb egérgombbal a Solution Explorerben a project nevén a megjelenő helyi menüben válasszuk ki az Add menüpontot, majd Class… menüpontot.
A megjelenő ablakban adjuk meg az osztály nevét, amely most legyen például a DataAccess.vb.
Ha ezzel megvagyunk, látunk egy üres osztály, ezt követően adjuk, hozzá a System.ServiceModel névteret az osztályunkhoz ( using System.ServiceModel; )
Az adatelérést biztosító osztályunknak így kell kinéznie.
Public Class DataAccess Private Shared _list As List(Of Person) Private Shared Function GetPersonList() As List(Of Person) If _list Is Nothing Then _list = New List(Of Person) With _list .Add(New Person(1, "Homer", "Simpson")) .Add(New Person(2, "Marge", "Simpson")) .Add(New Person(3, "Bart", "Simpson")) .Add(New Person(4, "Lisa", "Simpson")) .Add(New Person(5, "Maggie", "Simpson")) End With End If Return _list End Function Public Shared Function GetPerson(ByVal id As Integer) As Person Return (From p In GetPersonList() Where p.ID = id).FirstOrDefault End Function Public Shared Function GetPersons() As List(Of Person) Return GetPersonList() End Function End Class
<DataContract()> _ Public Class Person Private _id As Integer <DataMember()> _ Public Property ID() As Integer Get Return _id End Get Set(ByVal value As Integer) _id = value End Set End Property
Interfészhez ServiceContract attribútum hozzáadása, névtér cserével: http://tempuri.org <ServiceContract(Namespace:="http://demo.wcf.samples")> _ Public Interface IPerson <OperationContract()> _ Function GetPerson(ByVal id As Integer) As Person <OperationContract()> _ Function GetPersons() As List(Of Person) End Interface
Public Class PersonService Implements IPerson Public Function GetPerson(ByVal id As Integer) As Person _ Implements IPerson.GetPerson Return DataAccess.GetPerson(id) End Function Public Function GetPersons() As List(Of Person) _ Implements IPerson.GetPersons Return DataAccess.GetPersons() End Function End Class
Dim uri = New Uri("http://localhost:8080/demo/wcf/samples") Dim host As New ServiceHost(GetType(PersonService), uri) Try //Szolgáltatás végpont hozzáadása. WsHttpBinding, TcpBinding, ... Http kérések engedélyezése a kliensnek. host.AddServiceEndpoint(GetType(IPerson), New WSHttpBinding, "PersonService") Dim behavior As New ServiceMetadataBehavior() behavior.HttpGetEnabled = True host.Description.Behaviors.Add(behavior) Console.WriteLine("Szolgáltatás el fog indulni"); host.Open(); Console.WriteLine("Elindult a szolgáltatás"); Console.WriteLine("Nyomja meg az ENTER-t a leállításához.") Console.ReadLine() host.Close() Catch ex As CommunicationException Console.WriteLine("Error: {0}", ex.Message) host.Abort() End Try
<configuration> <system.serviceModel> <services> <!-- Megjegyzés: A szolgáltatásnévnek egyeznie kell a szolgáltatásimplementáció konfigurációs nevével. --> <service name="PersonService" behaviorConfiguration="MyServiceTypeBehaviors" > <!-- A következő végpont hozzáadása. --> <!-- Megjegyzés: A végpont hozzáadásához a szolgáltatásnak http típusú alapcímmel kell rendelkeznie. --> <endpoint contract="IMetadataExchange" binding="mexNamedPipeBinding" address="mex" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="MyServiceTypeBehaviors" > <!-- A következő elem hozzáadása a szolgáltatás viselkedéskonfigurációjához. --> <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/PersonService" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
Most, hogy elkészítettük a szerverünket készítsük el, hozzá a kliensalkalmazást is.
Indítsuk el a Visual Studio 2008-at rendszergazdai módban, majd a válasszuk ki a File -> New -> Project… menüpontot és a megjelenő ablakban válasszuk ki a templatek közül a Console Application –t.
A neve legyen például: Wcf.Client, majd kattintsunk az OK gombra.
Ezután magkapjuk a visual studio által legenerált kódvázat.
Ha ezzel megvagyunk, kattintsunk jobb egérgombbal a Solution Explorerben a References-re és válasszuk ki a megjelenő helyi menüből az Add Service Reference menüpontot.
A megjelenő ablakban adjuk meg azt a címet, amelyen a szolgáltatás interfészét elérhetjük.
A cím jelen esetben a http://localhost:8080/PersonService majd kattintsunk a Go nyomógombra.
Néhány másodpercen belül, ha a címen megtalálta a szolgáltatást a következő képernyő fogad minket.
Ha ezt látjuk, akkor a Namespacehez adjunk egy tetszőleges választott nevet.
Ez lesz a névtere a szolgáltatásunknak. Majd kattintsunk az OK gombra.
Figyelem!
Szerveralkalmazásnak futnia kell, ahhoz, hogy elérjük és lekérjük az adatokat!
Amennyiben idáig eljutottunk, akkor már a kliens eléri a szerver oldalt.
Képes hívni a listázó és az elemet visszaadó szerver oldali metódusokat.
A tényleges kód, amely ezt elvégzi, nagyon rövid, mindössze néhány sor az egész:
Public Sub Main() Dim client As New ServiceReference1.PersonClient() Dim pers As ServiceReference1.Person = client.GetPerson(1) If Not pers Is Nothing Then Console.WriteLine("Person with ID=1 is {0} {1}", _ pers.FirstName, pers.LastName) End If Console.WriteLine("Person list") For Each p In client.GetPersons() Console.WriteLine("{0}: {1} {2}", _ p.ID, p.FirstName, p.LastName) Next Console.ReadLine() End Sub
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="WSHttpBinding_IPerson" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" /> </security> </binding> </wsHttpBinding> </bindings> <client> <endpoint address="http://localhost:8080/demo/wcf/samples/ServiceLib.PersonService" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IPerson" contract="ServiceReference1.IPerson" name="WSHttpBinding_IPerson"> <identity> <userPrincipalName value="localhost" /> </identity> </endpoint> </client> </system.serviceModel>
A .NET technológia lehetővé teszi, hogy különböző nyelveken megírt programot egy más nyelvben felhasználjunk. Például megírunk egy osztályt Visual Basic nyelven, majd később ugyanezt az osztályt használjuk a C# nyelvben. A következő példában egy négyzet osztályt írunk meg Visual Basic nyelven.
'Négyzet osztály Public Class Square 'Oldal attribútum létrehozása Private pvt_a As Integer Property a() As Integer Get Return pvt_a End Get Set(ByVal Value As Integer) pvt_a = Value End Set End Property 'Konstruktor Public Sub New(ByVal value As Integer) a = value End Sub 'Kerületet számító metódus Public Function Perimeter() As Integer Return 4 * a End Function 'Területet számító metódus Public Function Area() As Integer Return a * a End Function Public Overrides Function ToString() As String Dim text As String text = "a: " & a & ", perimeter: " & Perimeter() & ", area: " & Area() Return text End Function End Class
using System; using System.Collections.Generic; using System.Linq; using System.Text; using VB; //itt importáljuk be a VB-ben megírt osztályt namespace CsharpWithVB { class Program { static void Main(string[] args) { Square square = new Square(5); //using VB-nek köszönhetően használható Console.WriteLine("Square:"); Console.WriteLine(square.ToString()); Rectangle rect = new Rectangle(3, 4); Console.WriteLine("Rectangle:"); Console.WriteLine(rect.ToString()); Console.ReadLine(); } } //Téglalap osztály létrehozása a Square osztályból való származtatással class Rectangle : Square { private int b; public Rectangle(int a, int b) : base(a) { this.b = b; } //Kerületet számító metódus public new int Perimeter() { return 2 * (a + b); } //Területet számító metódus public new int Area() { return a * b; } public new string ToString() { return "a: " + a + ",b: " + b + ", perimeter: " + Perimeter() + ", area: " + Area(); } } }
A Visual Studio 2008-as változatától kezdve használhatunk a nyelvben a funkcionális programoknál már jól ismert lambda kifejezéseket. A lambda kifejezés egy név nélküli eljárás vagy függvény, melyet ott használhatunk, ahol a delegáltakat is (Ez alól kivételt képez a RemoveHandler kifejezés). Ezek a kifejezések lehetnek egy- vagy többsorosak is. Lambda kifejezést a Sub vagy Function kulcsszó használatával definiálhatunk, mintha egy szokványos eljárást vagy függvényt definiálnánk. A példában szereplő két lambda kifejezés azonos:
Dim fuggveny1 = Function(x) x + 1
Dim fuggveny2 = Function(x)
Return x + 1
End Function
Az előző példánkban a kifejezést értékül adtuk egy delegate-nek, de lambda függvényt meg is hívhatjuk:
Console.WriteLine((Function(Num As Integer) num + 2)(40))
Mint látható a lambda kifejezések nagyon hasonlóak a nyelvben használt eljárásokhoz és függvényekhez, de számos különbség van köztük:
Egy típus akkor nullable, ha értéket adhatunk neki, vagy null-ra állíthatjuk, ami azt jelenti, hogy nincs értéke. Ennél fogva ezzel a típussal egyben azt is kifejezhetjük, hogy adott-e érték. Például a String típus nullable, de az Int32 nem. Egy érték típus nem lehet nullable, mert a mérete akkora, hogy csak a típusnak megfelelő értékeket tárolja, nincs kapacitása a null érték tárolására.
A Nullable
A Nullable típusok olyan dolgokat reprezentálnak, melyek a körülményeknek megfelelően léteznek vagy nem. Például egy HTML tag létezhet egy másik tag-en belül, de nem minden esetben, vagy egy adatbázis valamelyik oszlopa felvehet null értéket, mert az érték hiányát jelöli.
A Nullable struktúrának két fontos tulajdonsága van, a HasValue és a Value. Ha a Nullable
A metódus kiterjesztések segítségével a fejlesztők könnyedén adhatnak saját funkcionalitást olyan adattípusokhoz, melyeket már definiáltak, anélkül hogy származtatniuk kellene. A metódus kiterjesztések lehetővé teszik, hogy olyan metódust írjunk, amely úgy hívódik meg, mintha az osztály adott példányának a metódusa lenne.
A metódus kiterjesztés csak Sub eljárás lehet vagy egy Function függvény. Nem lehet definiálni kiterjesztés tulajdonságot, mezőt vagy eseményt. Minden ilyen eljárást vagy függvényt meg kell jelölni az
A példában a Print eljárással terjesztjük ki a String osztályt, mely a konzolra írja az adott szöveget:
Imports System.Runtime.CompilerServices
Module StringExtensions
Public Sub Print(ByVal aString As String)
Console.WriteLine(aString)
End Sub
End Module
Metódus kiterjesztést definiálhatsz a legtöbb típusra, melyet megadhatsz paraméterként is:
Mivel az első paraméter adja meg a kiterjesztett típust, ezért ennek a megadása kötelező, így nem írhatjuk elé az Optional és a ParamArray kulcsszót.
A metódus kiterjesztések segítségével könnyedén terjeszthetünk ki meglévő típusokat. A sikeres használatukhoz azonban néhány dolgot figyelembe kell vennünk. Általánosságban a külső osztályhoz adott kiterjesztések több hibalehetőséget hordoznak magukban, mint a saját magunk által írt osztályokhoz adott kiterjesztések, mivel az objektumok belső viselkedését nem ismerjük.
Amennyiben két kiterjesztett metódus azonos szignatúrával rendelkezik és mindkét kiterjesztés elérhető, akkor a magasabb precedenciájú metódus kerül meghívásra. A következő lista mutatja a precedencia sorrendet, kezdve a legnagyobb értékűvel:
Ha a precedencia alapján sem egyértelmű a hívott kiterjesztés, akkor egyértelműen azonosíthatjuk a metódust az őt tartalmazó modullal, például ha a StringExtensions modulból szeretnénk használni a kiterjesztést, akkor használhatjuk a StringExtensions.Print(valami) kifejezést a valami.Print() helyett.
A .NET keretrendszer egyik követelménye, hogy a minden terjeszthető kód egységnek (szerelvény) rendelkeznie kell úgynevezett metaadatokkal, melyek jellemzik a szerelvényt és a benne felhasznált típusokat. A Reflection nem más, mint ezeknek a metaadatoknak a vizsgálata. Erre a .NET-ben a System.Reflection névtér szolgáltat eszközöket. Első példánkban nézzük meg, hogyan lehet egy szerelvény minősített nevét lekérdezni:
Dim AssemblyPath As String
AssemblyPath = "C:\Pelda\bin\Szerelveny.dll"
Dim asm As [Assembly] = [Assembly].LoadFrom(AssemblyPath)
Console.WriteLine("Szerelveny neve: " & asm.FullName)
A példánkban az Assembly osztály neve kapcsos zárójelek között szerepel, mivel a Visual Basic .NET nyelvben az Assembly egy kulcsszó is, így viszont osztályként hivatkozunk rá. A példakódban a betöltést a LoadFrom metódussal végezzük, majd a visszatérített Assembly osztály nevét a FullName tulajdonsággal kérdezzük le. Az Assembly számunkra még 3 érdekes metódust is tartalmaz, melynek segítségével különféle szerelvényeket kérhetünk le:
A keretrendszerben a szerelvények között lehetnek függőségek, melynek listáját a GetReferencedAssemblies() metódussal kérdezhetjük le.
A Reflection egyik leghasznosabb felhasználási területe, hogy futás közben információkat tudunk lekérdezni egy szerelvényben lévő típusokról, így akár írhatunk alkalmazásokat, melyek a publikus metódusok alapján dokumentálják szerelvényünket. Ennek a technológiának segítségével futás közben dinamikusan példányosíthatunk osztályokat és meg is hívhatjuk ezeknek az osztályoknak a metódusait.
A System.Type segítségével kérdezhetünk le típus információkat. Egy szerelvényben foglalt típusok listáját lekérdezhetjük az Assembly osztály GetTypes metódusával. Amennyiben egy meglévő típusról szeretnénk típusinformációkat kinyerni, használhatjuk a GetType eljárást:
Dim t1 As Type = GetType(Integer)
Console.WriteLine(t.FullName)