Märkus.
Juurdepääs sellele lehele nõuab autoriseerimist. Võite proovida sisse logida või kausta vahetada.
Juurdepääs sellele lehele nõuab autoriseerimist. Võite proovida kausta vahetada.
Märkus.
Kogukonna huvirühmad on nüüd liikunud Yammerist Microsoft Viva Engage'i. Viva Engage kogukonnaga liitumiseks ja viimastes aruteludes osalemiseks täida vorm Request access to Finance and Operations Viva Engage Community ning vali kogukond, kuhu soovid liituda.
Selles artiklis kirjeldatakse X++-i muutujaid.
- Muutuja on identifikaator, mis osutab mäluasukohale, kus talletatakse kindla andmetüübi teavet. Suurus, täpsus, vaikeväärtus, kaudsed ja otsesed teisendusfunktsioonid ning vahemik sõltuvad muutuja andmetüübist.
- Muutuja ulatus määratleb koodi ala, kus üksusele juurde pääseb.
- Eksemplarimuutujad deklareeritakse klassideklaratsioonides ja neile pääsete juurde klassi mis tahes meetodite või klassi laiendavate meetodite abil.
- Kohalikele muutujatele pääseb juurde ainult selles plokis, kus need määratlesite.
- Muutuja deklareerimisel eraldate mälu ja lähtestate muutuja vaikeväärtusele.
- Deklareerimislause osana saate määrata väärtused nii staatilistele väljadele kui ka eksemplariväljadele.
- Muutujaid saate deklareerida meetodi koodiplokis suvalises kohas. Te ei pea neid meetodi alguses deklareerima.
- Konstandid on muutujad, mille puhul ei saa muutuja deklareerimisel väärtust muuta. Nad kasutavad võistlusmärksõna või kirjutuskaitstud märksõna.
- Konstandid erinevad kirjutuskaitstud väljadest ainult ühel viisil. Kirjutuskaitstud väljadele saate väärtuse määrata ainult üks kord ja see väärtus ei muutu kunagi. Välja väärtuse saate määrata kas teksti sees, välja deklareerimiskohas või konstruktoris.
Kui deklareerite hallatavate tüüpide muutujaid, mis pole X++-s loodud, on teil kaks võimalust. Saate deklareerimisel tüübinimed täielikult määrata, kaasates täisnimeruumi, või lisada failile lauset kasutades ja seejärel jätta nimeruum tüübi nimest välja.
Muutujate näited
// An example of two valid variable names.
str variableName;
CustInfo custNumber;
// An example of simultaneously declaring and initializing a variable.
real pi = 3.14159265359; // Assigns value of pi to 12 significant digits.
// An example of initializing an object by using the new method on the class.
Access accessObject = new Access(); // Simple call to the new method in the Access class.
// An example of multiple declarations using integers.
int i,j; // Declares 2 integers, i and j.
// An example of multiple declarations using an array.
int a[100,5], b=1; // Declares array with 100 integers with 5 in memory and b as an integer with value 1.
// An example of how variable scopes work.
class ScopeExample
{
// The variable a is declared within the class.
int a;
// Because the method below is declared within the class,
// it can access all the variables defined within the class.
void aNewMethod()
{
// The variable b is declared within the method.
// It can only be accessed by this method.
int b;
}
}
// An example of an assignment of field members inline.
public class FieldAssignmentExample
{
int field1 = 1;
str field2 = "Banana";
void new()
{
// ...
}
}
class ConstantExample
{
// An example of a constant being declared at the class level.
public const str MyContent = 'SomeValue';
public int ResultSoFar()
{
return 1;
}
}
// The constants can then be referenced by using the double-colon syntax.
str value = ConstantExample::MyContent;
// If you're in the scope of the class where the const is defined,
// you can omit the type name prefix (ConstantExample in this example).
// An example of the using clause where the alias can denote
// namespaces and classes.
using System;
using IONS=System.IO; // Namespace alias.
using Alist=System.Collections.ArrayList; // Class alias.
public class NamespaceExample
{
public static void Main(Args a)
{
Int32 I; // Alternative to System.Int32.
Alist al; // Using a class alias.
al = new Alist();
str s;
al.Add(1);
IONS.Path::ChangeExtension(@"c:\tmp\test.xml", ".txt");
}
}
Var
Muutuja saate deklareerida ilma muutuja tüüpi selgesõnaliselt esitamata, kui kompilaator saab lähtestamisavaldisest tüübi määratleda. Muutuja on ikka tugevalt tipitud ühte üheselt mõistetavasse tüüpi.
Muutujat var saab kasutada ainult deklaratsioonides, kus on esitatud lähtestusavaldised. Kompilaator tuletab tüübi lähtestusavaldisest. Mõnel juhul võib selline lähenemine muuta koodi lugemise lihtsamaks.
Kasutage funktsiooni var kohalike muutujate deklareerimiseks sellistes olukordades:
- Kui muutuja tüüp on ülesande paremast servast ilmne
- Kui täpne tüüp pole oluline
- Tsükliloendurite deklaratsioonid
- Ühekordseks kasutamiseks mõeldud objektide puhul lausete abil
Ärge kasutage muutujat var , kui tüüp pole lähtestusavaldisest eemaldatud.
var näited
// When the type of a variable is clear from
// the context, use var in the declaration.
var var1 = "This is clearly a string.";
var var2 = 27; // This is an integer (not a real).
var i = System.Convert::ToInt32(3.4);
// Don't use var when the type of the variable is not clear
// from the context. Use an explicit type instead.
int var4 = myObject.ResultSoFar();
Deklareeri kõikjal
Nüüd saate deklaratsioone esitada kõikjal, kus saate deklaratsioone esitada. Deklaratsioon on syntaktiliselt avaldus, seega on see deklaratsioonilause.
Enne muutuja kasutamist saate esitada deklaratsioonid ja te ei pea kõiki muutujaid ühes kohas deklareerima. Seetõttu on teil täpne kontroll muutujate ulatuse üle.
Saate anda muutujatele väiksemaid ulatusi, millest väljaspool ei saa muutujatele viidata. Muutuja eluiga on ulatus, milles see on deklareeritud. Ulatused saate käivitada plokitasemel (liitlausetes), lausetes ja lausete kasutamisel .
Ulatuse väikseks muutmisel on mitmeid eeliseid.
- Loetavus on täiustatud.
- Vähendate ohtu, et muutujat kasutatakse koodi pikaajalisel säilitamisel sobimatul viisil uuesti.
- Seda on hõlpsam refaktorkoodina kasutada. Koodis saate kopeerida, ilma et peaksite muretsema selle pärast, et muutujaid võidakse uuesti kasutada kontekstis, kus neid ei tohiks uuesti kasutada.
Järgmises näites deklareerite tsükliloenduri for-lauses, milles te seda kasutate.
void MyMethod()
{
for (int i = 0; i < 10; i++)
{
info(strfmt("i is %1", i));
}
}
Muutuja ulatus on lause enda jaoks ning see sisaldab tingimuseavaldist ja tsükli värskendusosi. Seda väärtust ei saa kasutada väljaspool seda ulatust.
Järgmises näites tagastab kompilaator teabelause jõudmisel järgmise tõrketeate: "'i' pole deklareeritud".
void MyMethod()
{
for (int i = 0; i < 10; i++)
{
if (i == 7)
{
break;
}
}
// The next statement causes a compiler error.
info(strfmt("Found: %1", i));
}
Muutujaid saate kasutada ka lause abil , nagu on näidatud järgmises näites.
static void AnotherMethod()
{
str textFromFile;
using (System.IO.StreamReader sr = new System.IO.StreamReader("c:\\test.txt"))
{
textFromFile = sr.ReadToEnd();
}
}
Kui kasutate objekti, mis juurutab IDisposable'i, deklareerige ja lähtestage see objekt lauses . Lause using kutsub objekti meetodit Dispose õigesti, isegi kui objekti meetodite kutsumisel ilmneb erand. Sama tulemuse saavutamiseks paigutage objekt katseplokki ja kutsuge siis konkreetselt käsu likvideeriminelõpuks plokis. Tegelikult tõlgib kompilaator kasutamislause just sellisel viisil.
Järgmises näites on mõned funktsioonid, mida selles jaotises kirjeldatakse.
// loop variable declared within the loop: It will
// not be misused outside the loop
for(int i = 1; i < 10; i++)
{
// Because this value is not used from outside the loop,
// its declaration belongs in this smaller scope.
str s = int2str(i);
info(s);
}
Segaduse vältimiseks tagastab kompilaator tõrketeate, kui proovite juurutada muutujat, mis peidab mõne muu muutuja ümbritsevas ulatuses või isegi samas ulatuses. Näiteks järgmine kood põhjustab kompilaatorile järgmise diagnostikateate: "Kohalikku muutujat nimega "i" ei saa selles ulatuses deklareerida, kuna selle tähendus oleks "i", mida juba kasutatakse ema- või praeguses ulatuses millegi muu tähistamiseks."
{
int i;
{
int i;
}
}
Konstandid, kirjutuskaitstud muutujad ja makrod
Keel toetab täielikult makrode mõistet. Konstandid pakuvad makrode ees järgmisi eeliseid.
- Konstanti saate lisada dokumentatsiooni kommentaari, kuid mitte makro väärtusele. Lõpuks võtab keeleteenus selle kommentaari üles ja annab kasutajale kasulikku teavet.
- IntelliSense tuvastab konstandi.
- Konstandile viidatakse ristviitena. Seetõttu leiate kõik viited kindlale konstandile, kuid mitte makrole.
- Konstandile kehtivad juurdepääsu muutefunktsioonid. Saate kasutada privaatseid, kaitstud ja avalikke muuteid. Makrode hõlbustusfunktsioonid pole täpselt määratletud.
- Püsivatel muutujatel on ulatus, makrodel aga ulatus puudub.
- Siluris kuvatakse konstandi või kirjutuskaitstud muutuja väärtus.
Makrod, mille määratlete klassiulatustes (st klassideklaratsioonides), on tegelikult saadaval kõigis tuletatud klasside meetodites. See funktsioon oli algselt viga pärand kompilaatori makro rakendamisel. Paljud programmeerijad aga kasutavad seda nüüd ära. X++ kompilaator järgib endiselt seda funktsiooni, kuid ei kirjuta uut koodi, mis seda kasutab. See funktsioon mõjutab oluliselt ka kompilaatori jõudlust.
Soovi korral saate kasutada makrot klassideklaratsioonide tasemel, kuid konkreetse viitega selle makro väärtusele. Selline lähenemine ei mõjuta kompilaatori jõudlust. Saate lubada olemasolevate standardmakrode arengus ristviited (ja kõik püsiva muutuja võimalused).
private const int RetryNum = #OCCRetryCount#RetryNum;
Konstante saate deklareerida klassi tasemel, nagu on näidatud järgmises näites.
private const str MyConstant = 'SomeValue';
Konstantidele viitamiseks saate kasutada topeltkoolonit (::) süntaksit.
str value = MyClass::MyConstant;
Kui olete selle klassi ulatuses, kus te konstandi määratlete, võite jätta välja tüübi nime eesliite (eelmises näites MyClass ). Seetõttu saate hõlpsalt rakendada makroteegi mõistet. Makrotähiste loendist saab klass, millel on avalikud võistlusmääratlused .
Konstante saate määratleda ka ainult muutujatena. Kompilaator säilitab invariandi, nii et väärtust ei saa muuta.
{
const int Blue = 0x0000FF;
const int Green = 0x00FF00;
const int Red = 0xFF0000;
}
Kirjutuskaitstud väljadele saate väärtuse määrata ainult üks kord ja see väärtus ei muutu kunagi. Välja väärtuse saate määrata kas teksti sees, välja deklareerimiskohas või konstruktoris.
Andmetüüpide tühiväärtused
Paljud teised andmebaasihaldussüsteemid (DBMS) toetavad nullväärtuste mõistet, kuid X++ ei toeta seda mõistet. X++ muutujal on alati tüüp ja väärtus. Iga andmetüübi puhul peetakse ühte väärtust nullväärtuseks (nt tabelimeetodi validteField käitamisel).
| Tüüp | Väärtus, mida käsitletakse tühiväärtusena |
|---|---|
| Kuupäev | 1900-01-01 |
| Loend | Element, mille väärtuseks on seatud 0 |
| Täisarv | 0 |
| Tegelik | 0.0 |
| String | Tühi string |
| Aeg | 00:00:00 |
| Utcdatetime | Mis tahes väärtus, mille kuupäevaosa väärtuseks on määratud 1900-01-01, sõltumata kellaajaosa väärtusest. Näiteks väärtust 1900-01-01T22:33:44 käsitletakse tühiväärtusena. Pange tähele, et lause x++ print kuvab suvalise väärtuse utcDateTime , mille kuupäevaosa väärtuseks on seatud 1900-01-01 . Ainult meetod Global::info kuvab väärtuse 1900-01-01T00:00:00 tühjana. See väärtus on meetodi DateTimeUtil::MinValue väärtus. |
Kui meetod validteField kontrollib, kas kasutaja sisestab väärtuse kohustuslikule väljale, ei aktsepteerita väärtust 0täisarvutüübi väljal, esimest kirjet ei aktsepteerita loenditüübi väljal jne. Lisaks annavad SQL X++ lausetes eelmises tabelis loetletud väärtused loogikavõrdluses väära tulemi. Kuid mitte-SQL X++ lausetes töötavad nende väärtustega võrdsed ja relatsioonilised tehtemärgid samamoodi nagu muude väärtustega. Ümbrise tüübi muutujad ning tabelitüübi klassid ja muutujad võivad traditsioonilises DBMS-i tähenduses olla nullväärtusega. Tabelitüüp on tühiväärtusega, kui kõigil selle väljadel on tühiväärtus.
Casting
Määramine tähendab muutujate vahelisi määramisi, mille deklareeritud tüübid on mõlemad samas pärilusahelas. Valatud on kas alla- või ülesminek. Kaaluge järgmist klassihierarhiat.
MotorVehicle'i klass ei ole seotud klassiga Animal, kuigi mõlemad pärinevad Object'ist. Kui määrate tuletatud tüübi avaldise põhitüübile, toimub see järgmiselt.
Animal a = new Horse();
Kui määrate tuletatud muutujale põhitüübiga avaldise, tehakse seda allapoole .
Horse h = new Animal();
X++ toetab nii üles- kui ka allahäälestust. Allakukkumised on aga ohtlikud ja neid tuleks võimalusel vältida. Eelmises koodis esitatud näide nurjub InvalidCastException käitusajal, kuna ülesandel pole mõtet. X++ toetab hilinenud sidumist teatud tüüpidega (nt object ja formrun). See tugi tähendab, et kompilaator ei diagnoosi kompileerimisajal ühtegi tõrget, kui kuvatakse meetod, mida kutsutakse nendel tüüpidel, kui seda meetodit pole tüübi jaoks selgesõnaliselt deklareeritud. Eeldatakse, et arendaja teab, mida nad teevad. Näiteks võib vormil olla järgmine kood.
Object o = element.args().caller();
o.MyMethod(3.14, “Banana”);
Kompilaator ei saa kontrollida meetodi parameetreid ega tagastada väärtusi MyMethod , kuna seda meetodit ei deklareerita objektiklassis. Käitusajal kasutatakse kõne peegeldust, mis on palju aeglasem kui kõned, mis ei vaja peegeldust. Kontrollitakse meetodeid, mis on määratletud hilise sidumise tüüpide puhul. Näiteks kõne järgmises ToString näites:
o.ToString(45);
põhjustab kompileerimistõrke:
'Object.toString' expects 0 argument(s), but 1 specified.
ToString kuna meetod on määratletud klassisobject. On üks erinevus rakenduse X++ (AX2012 ja varasemate) varasemates versioonides, mis on seotud asjaoluga, et meetodeid saab kutsuda seostamata objektidele, kui meetodi nimi oli õige, isegi kui parameetriprofiilid ei olnud täiesti õiged. See tugi pole enam saadaval.
Näide – casting
public class MyClass2
{
public static void Main(Args a)
{
Object obj = new Car();
Horse horse = obj; // exception now thrown
horse.run(); // Used to call car.run()!
}
}
Kasutage oma koodis tehtemärke is ja as tehtemärke. Kasutage tehtemärki is , et kontrollida, kas esitatud avaldis on teatud tüüpi (sh tuletatud tüübid). Tehtemärk as sooritab antud tüübile kirjutamise ja tagastab tühiväärtuse, kui esitamine pole võimalik.