Type conversies. Conversie van gegevenstypen

Bij het programmeren is het vaak nodig om berekeningen uit te voeren op variabelen van het ene type, en als resultaat een ander type te verkrijgen. Als u bijvoorbeeld gehele getallen deelt, krijgt u een reëel getal. Wanneer een waarde van het ene type wordt opgeslagen in een variabele van een ander type, wordt een gegevenstypeconversie uitgevoerd. In C# wordt dit via verschillende mechanismen geïmplementeerd.

Impliciete conversie van gegevenstypen

Een impliciete conversie vindt plaats wanneer een waarde wordt opgeslagen in een variabele van een ander type zonder dat deze in de code is gespecificeerd.

Als de C#-compiler een gegevenstype automatisch wil converteren, moeten er twee voorwaarden vervuld zijn:

  • Het waardetype en het variabeletype moeten compatibel zijn met elkaar;
  • Het bereik van mogelijke waarden van een variabel type mag niet kleiner zijn dan dat van een waardetype.

Byte a = 15; byte b = 120; int c = a + b;

IN in dit voorbeeld rennen impliciete conversie , en variabele c zal uiteindelijk van het type int zijn. Dit is mogelijk omdat byte en int gehele getallen zijn, en het int-type het bytebereik volledig omvat.

Nog een voorbeeld:

Kort a = 815; ukort b = a;//Fout

Ook al ligt het nummer 815 in dit geval binnen het ukorte bereik er verschijnt een foutmelding. Dit komt door het feit dat de compiler voor expliciete conversie controleert alleen de bovenstaande voorwaarden en kijkt alleen naar typen, zonder aandacht te besteden aan specifieke waarden.

Expliciete conversie van gegevenstypen

Als niet aan de voorwaarden voor een impliciete conversie wordt voldaan, maar er wel een typeconversie moet worden uitgevoerd, wordt er gebruik gemaakt van een typecast. Dit is een indicatie doeltype, waarin het berekeningsresultaat, dat tussen haakjes vóór de uitdrukking staat, moet worden omgezet.

Int d = 13; int c = 4; var e = (dubbel)d/c;

Dus de variabele e krijgt typ dubbel en de waarde is 3,25. Als we geen conversie zouden gebruiken, zou deze variabele een int-type en een waarde van 3 hebben volgens de regels voor het delen van gehele getallen in C#.

Nog een voorbeeld:

Ukort getal = 257; dubbele dbl = 34,9318; int rnd = (kort) dbl; // Krijgt de waarde 34 byte what = (byte) num; // Krijgt de waarde 1 toegewezen

In het geval van rnd, wordt geëxecuteerd volgende regel: Bij het converteren van getallen met drijvende komma naar gehele getallen, wordt hun fractioneel deel weggegooid.

En in het geval van wat alles is een beetje ingewikkelder. Bij het uitvoeren van een expliciete conversie let de compiler niet op typebereiken. En tijdens de uitvoering van het programma, als er een poging wordt gedaan om binnen te komen variabele waarde, die zich niet binnen zijn bereik bevindt (met een hogere bitdiepte), worden alle bits van hoge orde gewist. Nummer 257 inch binaire representatie type ushort ziet eruit als 00000001 00000001. Bij conversie naar byte blijft alleen de laatste byte 00000000, dat wil zeggen 1, over.

Een conversie waarbij het bereik van het variabeletype het bereik van het waardetype niet volledig dekt, wordt een vernauwingsconversie genoemd. Om gegevensverlies te voorkomen, zoals in het vorige voorbeeld, moet u een overloopcontrole gebruiken.

Het beperken van de overstroom van gegevensconversies

Het is duidelijk dat u plaatsen in de code waar gegevensverlies als gevolg van overflow kan optreden, niet kunt negeren. Anders kunnen variabelen onverwachte waarden aannemen, wat de werking van het programma zal beïnvloeden, en de oorzaak van de fout zal vrij moeilijk te achterhalen zijn.

Standaard wordt het optreden van een overloop genegeerd. Om er zeker van te zijn dat er in dit geval een passende uitzondering wordt gegenereerd, wordt het gecontroleerde sleutelwoord gebruikt. Het kan vóór een bepaalde uitdrukking worden geplaatst of om er een codeblok mee aan te duiden. Als er vervolgens een uitzondering optreedt, kan deze met de constructie worden afgehandeld proberen en vangen.

Willekeurig rnd = nieuw Willekeurig(); int groter = rnd.Volgende(99999); // Genereert een willekeurig getal van 0 tot 99999, maar kleiner; try ( kleiner = gecontroleerd((kort) groter); ) catch (System.OverflowException e) ( Console.WriteLine('Overflow verhoogd door gecontroleerd op kleiner: ' + e.ToString()); // Prints //een bericht over dat een uitzondering werd afgehandeld kleiner = -1;

groter is willekeurig nummer van 0 tot 99999. Als deze waarde het bereik van het korte type overschrijdt, wordt er een uitzondering verwerkt System.OverflowException en variabel kleiner krijgt de waarde -1 toegewezen. Als er geen overflow optreedt, is er geen uitzondering en neemt de kleinere variabele eenvoudigweg de waarde aan van de grotere variabele, maar dan in het type kort.

is exploitant

Om te controleren of een object in C# naar een bepaald type gecast kan worden, wordt de operator gebruikt is. Het controleert of een object een instantie is van het opgegeven type zelf of een afgeleide ervan. Het resultaat van een binaire bewerking met de operator is is Booleaanse waarde(waar of onwaar).

Een voorbeeld van het gebruik van de operator is:

Klasse Samle1 () klasse Samle2 () : Sample1 () // Erft klasse Sample1 klasse Sample3 () Samle1 t1 = new Samle1(); Monster2 t2 = nieuw Monster2(); Voorbeeld3 t3 = nieuw Voorbeeld3(); teken t4 = 't'; if (t1 is Sample1) ( Console.WriteLine(“t1 is Sample1”); ) // Wordt afgedrukt if (t2 is Sample1) ( Console.WriteLine(“t2 is Sample1”); ) // Wordt afgedrukt if ( t3 is Sample1) ( Console.WriteLine(“t3 is Sample1”); ) // Wordt niet afgedrukt als (t4 is Sample1) ( Console.WriteLine(“t4 is Sample1”); ) // Wordt niet afgedrukt

Exploitant als

De operator as wordt gebruikt om compatibele referentietypen te converteren. Opgemerkt moet worden dat als de conversie niet mogelijk is, er geen uitzondering wordt gegenereerd, maar wordt geretourneerd nulwaarde. Hiermee moet rekening worden gehouden bij het verwerken van het resultaat van de conversie met behulp van as.

Klasse SamleClass() object Arr = nieuw object; Arr = nieuwe VoorbeeldKlasse(); Arr = “welkom”; Arr = (kort) 654; Arr = nul; voor (byte i = 0; i< Arr.Length; i++) { string t1 = Arr[i] as string; SampleClass t2 = Arr[i] as SampleClass; if (t1 != null) { Console.WriteLine(“{0}: it’s a string ‘” + t1 + “’”, i+1); } else if (t2 != null) { Console.WriteLine(“{0}: it’s a SampleClass”, i+1); } else { Console.WriteLine(“{0}: it’s not string or SampleClass”, i+1); } }

De uitvoer van het voorbeeld zou als volgt zijn:

1: het is een SampleClass

2: het is een string "welkom"

3: het is geen string of SampleClass

4: het is geen string of SampleClass

Typen converteren met behulp van de Convert-klasse

De systeemklasse System.Convert bevat methoden die kunnen worden gebruikt om waarden te converteren basistypen gegevens, evenals systeemtype DatumTijd.

Overzetten bevat een reeks methoden zoals ToType, waarbij Type wordt vervangen door de systeemnaam van het doelwaardetype (bijvoorbeeld ToChar, ToInt32, ToBoolean). Met deze methoden kunt u alle mogelijke conversies uitvoeren vanuit standaard C#-typen.

De Convert.ChangeType-methode converteert elk object naar elk opgegeven type. Als er sprake is van een type-mismatch of overflow, genereert de methode een uitzondering.

Laten we verder gaan met voorbeelden. Klas Testen, met voorbeelden, is een reeks gegevens van verschillende typen waarop bewerkingen worden uitgevoerd die typeconversies illustreren. Hier is de klassebeschrijving

Testen: systeem gebruiken;
naamruimte TypesProject
{
openbare klasse testen{
/// < samenvatting>
/// een reeks scalaire velden van verschillende typen.
///
privébyte b= 255;
privé int x= 11 ;
privé uint ux= 1111 ;
privé vlotter= 5,5f;
privé dubbele dy= 5.55;
privéreeks s= "Hallo!";
privéreeks si= "25";
privé object obj= nieuw object();
// Hierna volgen de klassenmethoden, die onderweg worden vermeld
// beschrijvingen van voorbeelden
}
}

De klassegegevensset omvat scalaire gegevens van het rekenkundige type, gerelateerd aan waardetypen, variabelen van het tekenreekstype en type voorwerp, behorend tot referentietypen. Overweeg een gesloten (privé) methode van deze klasse - procedure Wie is wie met een formeel klassenargument Voorwerp. De procedure toont aan de console de naam van het argument dat eraan is doorgegeven, het type en de waarde ervan.

Hier is haar tekst:

/// < samenvatting>
/// De methode geeft informatie weer over het type en
/// de waarde van het daadwerkelijke argument. Formeel
/// argument heeft typevoorwerp. Feitelijke argumentatie
/// kan van elk type zijn, omdat dit altijd het geval is
/// impliciete conversie naar type is toegestaanvoorwerp.
///
/// Naamsecondeargument
/// Laten we zeggenargumentelktype
private void WhoIsWho(tekenreeksnaam, object willekeurig){
Console.WriteLine("type{0} is (1), waarde is{2}",
naam, any.GetType(), any.ToString());
}

Hier is een openstaande (publiek) klasse methode Testen, waarin de methode herhaaldelijk wordt aangeroepen Wie is wie met argumenten van verschillende typen:

/// < samenvatting>
/// krijg informatie over het type en de waarde
/// doorgegeven argument - variabele of expressie
/// samenvatting>
publieke leegte WhoTest(){
WholsWie("x", x);
WholsWho("ux", ux);
WieIsWie("y", y);
WieIsWie("dy", dy);
WieIsWie("s", s);
WieIsWie("11+ 5.55 + 5,5f", 11+ 5.55 + 5,5f);
obj= 11 + 5.55 + 5,5f;
WieIsWie(" obj", obj);
}

Merk op dat de entiteit elk- formeel klassenargument Voorwerp, die bij elke aanroep dynamisch het type verandert door te binden aan het object dat is opgegeven door het feitelijke argument. Daarom is het argumenttype dat naar de console wordt afgedrukt, het type van het daadwerkelijke argument. Merk ook op dat het van de klas is geërfd Voorwerp methode GetType retourneert het FCL-type, dat wil zeggen het type waarnaar het taaltype wordt weerspiegeld en waarmee het feitelijk wordt gebruikt werk in uitvoering bij het uitvoeren van de module. Bij de meeste oproepen is het feitelijke argument een variabele: de overeenkomstige klasse-eigenschap Testen, maar in één geval het gebruikelijke rekenkundige uitdrukking, automatisch geconverteerd naar een object. Een soortgelijke situatie doet zich voor bij het uitvoeren van een opdracht in de onderhavige procedure.

In afb. Figuur 11 toont de console-uitvoer die wordt verkregen bij het aanroepen van de methode WieTest in de bovenstaande procedure Voornaamst klas Klassiek.

Figuur 11. WhoTest-testresultaten afdrukken

Waar, hoe en wanneer worden typeconversies uitgevoerd?

De behoefte aan typeconversie ontstaat bij expressies, toewijzingen en vervanging van formele methodeargumenten door daadwerkelijke argumenten.

Als bij het evalueren van een expressie de operanden van de bewerking verschillende typen hebben, wordt het noodzakelijk om ze naar hetzelfde type te casten. Deze behoefte doet zich ook voor als de operanden van hetzelfde type zijn, maar niet consistent zijn met het type bewerking. Bij het uitvoeren van optellingen bijvoorbeeld operanden van het type byte moet naar type worden gegoten int, aangezien optelling niet via bytes wordt gedefinieerd. Bij het uitvoeren van een opdracht X= e brontype e en doeltype X moet worden overeengekomen. Op dezelfde manier moeten bij het aanroepen van een methode ook de typen bron en doel (de feitelijke en formele argumenten) consistent zijn.

Referentietypeconversies

Omdat bewerkingen op referentietypen niet zijn gedefinieerd (de uitzondering zijn tekenreeksen, maar bewerkingen daarop, inclusief toewijzing, worden uitgevoerd zoals op waardetypen), ontstaat de noodzaak daarvoor alleen tijdens toewijzingen en methodeaanroepen.

Typ Conversies in Expressies

In C# zijn dergelijke conversies onderverdeeld in impliciet en expliciet. Impliciete transformaties omvatten die transformaties waarvan het resultaat altijd succesvol is en niet leidt tot verlies van de nauwkeurigheid van de gegevens. Impliciete conversies worden automatisch uitgevoerd. Voor rekenkundige gegevens betekent dit dat bij impliciete conversies het bereik van het bestemmingstype het bereik bevat originele soort. Bijvoorbeeld conversie van type byte van soort int verwijst naar impliciet omdat het bereik van het type is byte is een subset van het bereik int. Deze conversie is altijd succesvol en kan niet leiden tot verlies van nauwkeurigheid.

Expliciete conversies omvatten toegestane conversies waarvan het succes niet gegarandeerd is of kan leiden tot verlies van nauwkeurigheid. Dergelijke potentieel gevaarlijke transformaties moeten expliciet door de programmeur worden gespecificeerd. Conversie van type int van soort byte is expliciet omdat het onveilig is en ertoe kan leiden dat aanzienlijke cijfers verloren gaan. Houd er rekening mee dat niet alle typen expliciete conversies hebben. In dit geval zijn andere typen conversiemechanismen vereist, die later zullen worden besproken.

Conversies binnen een rekenkundig type

Het rekenkundige type, zoals weergegeven in de gegevenstypetabel, is verdeeld in 11 subtypen. In afb. Figuur 12 toont een diagram van transformaties binnen een rekenkundig type.

Figuur 12. Hiërarchie van conversies binnen een rekenkundig type

Met het diagram in de afbeelding kunt u de reeks beantwoorden belangrijke kwesties gerelateerd aan het bestaan ​​van transformaties tussen typen. Als het diagram een ​​pad (pijlen) toont van type A naar type B, betekent dit dat er sprake is van een impliciete conversie van type A naar type B. Alle andere conversies tussen subtypen van het rekenkundige type bestaan, maar zijn expliciet. Merk op dat er geen cycli in het diagram voorkomen, alle pijlen zijn eenrichtingsverkeer, dus de conversie terug naar de impliciete moet altijd expliciet worden gespecificeerd.

Het in het diagram aangegeven pad kan behoorlijk lang zijn, maar dit betekent niet dat de hele reeks transformaties wordt uitgevoerd dit pad. De aanwezigheid van een pad duidt alleen op het bestaan ​​van een impliciete conversie, en de conversie zelf wordt slechts één keer uitgevoerd, van brontype A naar bestemmingstype B.

Soms doet zich een situatie voor waarin voor één brontype meerdere typen bestemmingen tegelijk kunnen bestaan ​​en het nodig is een doel te selecteren: het bestemmingstype. Dergelijke selectieproblemen ontstaan ​​bijvoorbeeld bij het werken met overbelaste methoden in klassen.

De regel voor het selecteren van een implementatie bij het aanroepen van een methode is als volgt: selecteer de implementatie waarvoor het in het diagram gespecificeerde transformatiepad korter is. Als er een exacte match is van de parameters per type (pad met lengte 0), dan zal uiteraard deze specifieke implementatie worden geselecteerd.

Laten we eens naar een ander testvoorbeeld kijken. Naar de klas Testen omvatte een groep overbelaste methoden OLaden met één en twee argumenten. Dit zijn de methoden:

/// < samenvatting>
/// Groep overbelaste methodenOLaden
/// met een of twee argumenten van het rekenkundige type.
/// Als er slechts één feitelijk argument is, wordt een van de volgende aangeroepen
/// methoden die het meest overeenkomen met het argumenttype.
/// Als u een methode met twee argumenten aanroept, is dit mogelijk
/// conflict bij het kiezen van de juiste methode, leidend tot
/// naar een compileerfout.
///
private void OLoad(float par){
Console.WriteLine("zwevende waarde{0}", par);
}
/// < samenvatting>
/// Overbelaste methodeOLadenmet één typeparameterlang
///
///
private void OLoad(lange par){
Console.WriteLine("lange waarde (0)", par);
}
/// < samenvatting>
/// Overbelaste methodeBijladenmet één typeparameterlang
///
///
private void OLoad(ulong par){
Console.WriteLine("ulong-waarde (0)", par);
}
/// < samenvatting>
/// Overbelaste methodeOLadenmet één typeparameterdubbele
///
///
privé leegte OnLoad (dubbele par){
Console.WriteLine("dubbele waarde (0)", par);
}
/// < samenvatting>
/// Overbelaste methodeOLadenmet twee typeparameterslangEnlang
///
///
///
private void OLoad(lange par1, lange par2){
Console.WriteLine("lange par1{0}, lange par2{1}", par1, par2);
}
/// < samenvatting>
/// Overbelaste methodeOLadenmet twee typeparameters
/// dubbeleEndubbele
///
///
///
private void OLoad(dubbele par1, dubbele par2){
Console.WriteLine("dubbele par1{0}, dubbele par2{1}", par1, par2);
}
/// < samenvatting>
/// Overbelaste methodeOLadenmet twee typeparameters
/// intEnvlot
///
///
///
private void OLoad(int par1, float par2){
Console.WriteLine("int par1{0}, vlotter par2{1}", par1, par2);
}

Al deze methoden zijn vrij eenvoudig. Ze rapporteren informatie over het type en de betekenis van de doorgegeven argumenten.

Hier is de testprocedure die de methode aanroept OLaden met verschillende aantallen en soorten argumenten:

/// < samenvatting>
/// Een overbelaste methode aanroepenOLaden. Afhankelijk van
/// het type en aantal argumenten dat een van de groepsmethoden wordt aangeroepen.
///
publieke leegte OLoadTest(){
OLaden(x);
OLaden(ux);
OLaden(y);
OLaden(dy);
// OLaden(x,ux);
// conflict: (int, zwevend)En(lang, lang)
OLoad(x, (zwevend) ux);
OLaden(y, dy);
OLaden(X, dy);
}

Houd er rekening mee dat een van de oproepen wordt becommentarieerd omdat deze in de uitzendfase tot een conflict leidt. Om het conflict bij het aanroepen van de methode op te lossen, was het nodig om een ​​expliciete argumentconversie op te geven, die wordt weergegeven in de regel na de commentaarregel. Testresultaat OLaadTest getoond in afb. 13.

Figuur 13. OLoadTest-testresultaten afdrukken

Expliciete conversies

Zoals reeds besproken kunnen expliciete conversies gevaarlijk zijn vanwege het verlies aan nauwkeurigheid. Daarom worden ze uitgevoerd onder leiding van de programmeur - hij draagt ​​de volledige verantwoordelijkheid voor de resultaten.

Conversies van tekenreekstypes

Een belangrijke klasse van conversies zijn conversies naar het stringtype en omgekeerd. Conversies naar het stringtype worden altijd gedefinieerd omdat alle typen afstammelingen zijn van de basisklasse Voorwerp, en daarom een ​​methode hebben NaarString(). Voor ingebouwde typen is een geschikte implementatie van deze methode gedefinieerd. In het bijzonder, voor alle subtypen van het rekenkundige type, de methode NaarString() retourneert een tekenreeks in een geschikte vorm die de corresponderende waarde van het rekenkundige type specificeert. Merk op dat de methode NaarString kan expliciet worden aangeroepen, maar als een expliciete aanroep niet is gespecificeerd, zal deze impliciet worden aangeroepen wanneer de context een conversie naar een stringtype vereist. Hier is een relevant voorbeeld:

/// < samenvatting>
/// Demonstratie van conversie naar een reeks gegevens van verschillende typen.
///
publieke leegte ToStringTest()
{
S= " VladimirPetrov ";
s1= " Leeftijd: ";
ux= 27;
S= S+ s1+ ux.ToString();
s1= " Salaris: ";
dy= 2700.50;
S= S+ s1+ dy;
WieIsWie(" S", S);
}

Het resultaat van deze procedure wordt getoond in Fig. 14.

Figuur 14. De resultaten van de ToStringTest-test afdrukken

Conversies van het stringtype naar andere typen, zoals rekenkunde, moeten expliciet worden uitgevoerd. Maar er zijn geen expliciete conversies tussen rekenkunde en strings. Er zijn andere mechanismen nodig, en C# heeft die. Voor dit doel kunt u de overeenkomstige klassenmethoden gebruiken Overzetten FCL-bibliotheek ingebouwd in de naamruimte Systeem. Laten we een overeenkomstig voorbeeld geven:

/// < samenvatting>
/// Demonstratie van het converteren van een string naar verschillende gegevenstypen.
///
publieke leegte FromStringTest(){
S= " Binnenkomenleeftijd ";
Console.WriteLine(s);
s1= Console.ReadLine();
ux= Convert.ToUInt32(s1);
WieIsWie("Leeftijd: ",ux);
S= "Voer salaris in";
Console.WriteLine(s);
s1= Console.ReadLine();
dy= Convert.ToDouble(s1);
WieIsWie("Salaris: ", dy);
}

Dit voorbeeld demonstreert console-invoer verschillende soorten. Gegevens gelezen van de console met behulp van de methode Leesregel of Lezen, zijn altijd een string, die vervolgens naar het gewenste type moet worden geconverteerd. Om dit te doen, roept u de overeenkomstige klassenmethoden aan Overzetten. Om de conversie te laten slagen, moet de string uiteraard een waarde bevatten in een formaat dat een dergelijke conversie mogelijk maakt. Merk bijvoorbeeld op dat bij het schrijven van de waarde van een getal een komma en geen punt moet worden gebruikt om het breukgedeelte te markeren; anders zal er een runtimefout optreden.

In afb. Figuur 15 toont de resultaten van uitvoer en invoer van gegevens vanaf de console wanneer deze procedure wordt uitgevoerd.

Figuur 15. De resultaten van de FromStringTest-test afdrukken

Typ conversies

Bij het programmeren worden waarden van variabelen van het ene type vaak toegewezen aan variabelen van een ander type. In het onderstaande codefragment bijvoorbeeld de gehele waarde typ int toegewezen aan een drijvende-kommavariabele van het type float:

Int ik; zweven f; ik = 10; f = ik; // wijs een geheel getal toe aan een float-variabele

Als compatibele gegevenstypen worden gemengd in dezelfde toewijzingsbewerking, wordt de waarde aan de rechterkant van de toewijzingsoperator automatisch geconverteerd naar het type dat aan de linkerkant is opgegeven. Daarom wordt in het bovenstaande codefragment de waarde van variabele i eerst geconverteerd naar float en vervolgens toegewezen aan variabele f. Maar vanwege strikte typecontrole zijn niet alle gegevenstypen in C# volledig compatibel, en daarom zijn niet alle typeconversies impliciet toegestaan. De typen bool en int zijn bijvoorbeeld incompatibel. Het is waar dat de conversie van incompatibele typen nog steeds kan worden bereikt door afgietsels. Typecasting betekent in wezen het expliciet converteren ervan.

Automatische typeconversie

Wanneer gegevens van het ene type worden toegewezen aan een variabele van een ander type, impliciete conversie typen vindt automatisch plaats onder de volgende omstandigheden:

  • beide typen zijn compatibel
  • het bereik van de getalweergave van het doeltype is groter dan dat van het brontype

Als aan beide voorwaarden is voldaan, dan uitbreidende transformatie. Het type int is bijvoorbeeld groot genoeg om alle geldige waarden van type byte te bevatten, en bovendien zijn zowel int als byte compatibele gehele typen en kunnen daarom impliciet worden geconverteerd.

Numerieke typen, zowel gehele getallen als drijvende komma, zijn redelijk compatibel met elkaar voor het uitvoeren van verbredende conversies. Laten we eens kijken naar een voorbeeld:

Systeem gebruiken; met behulp van System.Collections.Generic; met behulp van System.Linq; met behulp van System.Text; naamruimte ConsoleApplication1 ( class Program ( static void Main(string args) ( kort num1, num2; num1 = 10; num2 = 15; Console.WriteLine("(0) + (1) = (2)",num1,num2,Sum (num1,num2)); Console.ReadLine(); statische int Som(int x, int y) ( retour x + y; ) )

Merk op dat de Sum()-methode twee int-parameters verwacht. De methode Main() geeft echter feitelijk twee korte variabelen door. Hoewel dit misschien lijkt op een type-mismatch, zal het programma zonder fouten compileren en draaien en zal het 25 retourneren zoals verwacht.

De reden die de compiler zal aannemen deze code syntactisch correct, omdat gegevensverlies hier onmogelijk is. Omdat de maximale waarde (32767) die het korte type kan bevatten ruim binnen het bereik van het int-type ( maximale waarde dat is 2147483647), zal de compiler impliciet elke variabele van het type short uitbreiden naar het type int. Formeel wordt de term "extensie" gebruikt om te verwijzen naar een impliciete opwaartse beweging die niet tot gegevensverlies leidt.

Incompatibele typen casten

Hoewel impliciete typeconversies nuttig zijn, kunnen ze niet aan alle programmeerbehoeften voldoen, omdat ze alleen extensieconversies van compatibele typen toestaan. In alle andere gevallen moet u gebruik maken van typecasting. Brengen- dit is een opdracht voor de compiler om het resultaat van de evaluatie van een expressie naar het opgegeven type te converteren. En dit vereist expliciete typeconversie. Hieronder staat algemene vorm soort afgietsels:

(target_type) expressie

Hier doeltype geeft het type aan waarnaar het wenselijk is om de opgegeven expressie te converteren.

Als typecasting resulteert in beperkende transformatie, dan kan er informatie verloren gaan. Als gevolg van het casten van een long type naar een int type gaat bijvoorbeeld bepaalde informatie verloren als de waarde lange soort zal groter zijn dan het representatiebereik van getallen voor het int-type, aangezien de meest significante bits van deze numerieke waarde worden weggegooid. Wanneer een drijvende-kommawaarde wordt geconverteerd naar een geheel getal, gaat het fractionele deel van deze numerieke waarde verloren als gevolg van afkapping. Dus als u de waarde 1,23 toewijst aan een geheel getalvariabele, blijft als gevolg daarvan alleen het gehele deel van het oorspronkelijke getal (1) daarin achter en gaat het fractionele deel (0,23) verloren. Laten we eens kijken naar een voorbeeld:

Systeem gebruiken; met behulp van System.Collections.Generic; met behulp van System.Linq; met behulp van System.Text; naamruimte ConsoleApplication1 ( class Program ( static void Main(string args) ( int i1 = 455, i2 = 84500; decimaal dec = 7,98845m; // Cast twee getallen van het type int // om short Console.WriteLine((short)i1 te typen ) ; Console.WriteLine((short)i2); // Converteer een decimaal getal // naar int Console.WriteLine((int)dec) ) )

Het resultaat van dit programma zal zijn:

Houd er rekening mee dat de variabele i1 correct is geconverteerd naar het type short, omdat de waarde ervan ligt binnen het bereik van dit gegevenstype. Het converteren van dec naar int retourneerde het gehele deel van dat getal. Het converteren van variabele i2 heeft geresulteerd overloopwaarde 18964 (d.w.z. 84500 - 2*32768).

Het onderscheppen van beperkende datatransformaties

In het vorige voorbeeld is het casten van de variabele i2 naar type short niet acceptabel omdat ontstaat gegevensverlies. Om toepassingen te creëren waarin gegevensverlies niet kan worden getolereerd, biedt C# trefwoorden zoals gecontroleerd En niet aangevinkt, die ervoor zorgen dat gegevensverlies niet onopgemerkt blijft.

Als er geen passende corrigerende actie wordt ondernomen, treden overloop- en onderloopomstandigheden standaard op zonder dat er een fout ontstaat. Er zijn twee manieren om met overloop- en onderloopomstandigheden in uw toepassing om te gaan. Dit kan handmatig worden gedaan, afhankelijk van uw kennis en vaardigheden op het gebied van programmeren.

Het nadeel van deze aanpak is dat zelfs als er maximale inspanningen worden geleverd, een persoon nog steeds een persoon blijft en dat sommige fouten aan zijn ogen kunnen ontsnappen.

Gelukkig biedt C# het gecontroleerde sleutelwoord. Als een instructie (of instructieblok) is ingesloten in een gecontroleerde context, genereert de C#-compiler aanvullende CIL-instructies om te controleren op overloopomstandigheden die kunnen voortvloeien uit het optellen, vermenigvuldigen, aftrekken of delen van twee numerieke typen gegevens.

Als er tijdens runtime een overloopvoorwaarde optreedt, wordt er een uitzondering gegenereerd System.OverflowException. Laten we eens kijken naar een voorbeeld waarin we een uitzonderingswaarde naar de console sturen:

Systeem gebruiken; met behulp van System.Collections.Generic; met behulp van System.Linq; met behulp van System.Text; naamruimte ConsoleApplication1 ( class Program ( static void Main(string args) ( byte var1 = 250; byte var2 = 150; try ( byte som = gecontroleerd((byte)(var1+var2)); Console.WriteLine("Sum: (0 )", som); ) catch (OverflowException ex) ( Console.WriteLine(ex.Message); Console.ReadLine(); ) ) ) )

Het resultaat van dit programma:

Stel een projectbrede controle op overflowcondities in

Als u een applicatie bouwt waarbij u nooit wilt dat er een overflow optreedt, kan het zijn dat u hinderlijk veel regels code rond het gecontroleerde trefwoord moet plaatsen. In een dergelijk geval, als alternatieve optie ondersteund in de C#-compiler vlag/aangevinkt. Wanneer deze vlag wordt geactiveerd, wordt alles wat in de code voorkomt automatisch gecontroleerd op mogelijke overflow. rekenkundige bewerkingen, zonder toepassing voor elk van hen trefwoord gecontroleerd. Het detecteren van een overloop zorgt er op vergelijkbare wijze voor dat er tijdens runtime een overeenkomstige uitzondering wordt gegenereerd.

Om deze vlag in te schakelen Visuele Studio 2010, moet u de pagina met projecteigenschappen openen, naar het tabblad Bouwen gaan, op de knop Geavanceerd klikken en het vakje aanvinken in het dialoogvenster dat wordt geopend Controleer op rekenkundige overloop/onderloop:

Het is belangrijk op te merken dat C# een trefwoord levert niet aangevinkt, waarmee u in bepaalde gevallen het genereren van een overflow-uitzondering kunt uitschakelen.

Om het gebruik van de gecontroleerde en niet-gecontroleerde trefwoorden in C# samen te vatten: rekenkundige overflow wordt standaard genegeerd in de .NET-runtime. Als u afzonderlijke instructies moet afhandelen, moet u het trefwoord CHECK gebruiken, en als u alle overflow-gerelateerde fouten in uw toepassing wilt onderscheppen, moet u de vlag /checked inschakelen. Het ongecontroleerde sleutelwoord kan worden gebruikt als er een codeblok is waarin overflow legaal is (en er daarom niet voor zou moeten zorgen dat er tijdens runtime een uitzondering wordt gegenereerd).

Impliciete datatypeconversie wordt uitgevoerd door de C++-compiler, terwijl expliciete datatypeconversie door de programmeur zelf wordt uitgevoerd. Over datatypeconversie zal ik het volgende zeggen: “Het resultaat van elke berekening zal worden geconverteerd naar het meest nauwkeurige datatype van de datatypen die bij de berekening betrokken zijn.” Voor duidelijk voorbeeld Ik zal een tabel presenteren met gegevenstypeconversies. In de tabel zullen we de delingsoperatie beschouwen. Laten we als een geheel getal gegevenstype nemen int, Goed echte soort we zullen gegevens hebben vlot.

Tabel 1 - Expliciete en impliciete conversie van gegevenstypes in C++
X j Resultaat van deling Voorbeeld
dividend scheidingslijn privé x = 15 y = 2
int int int 15/2=7
int vlot vlot 15/2=7.5
vlot int vlot 15/2=7.5

De tabel laat zien dat als je de variabelen op verschillende plaatsen verandert, het resultaat hetzelfde blijft (in ons geval is dit het deeltal en de deler). Alles over impliciete datatypeconversie. Wat de expliciete conversie betreft, is het noodzakelijk om enkele manipulaties uit te voeren, waardoor het resultaat van de berekening wordt gewijzigd. De eenvoudigste manier om gegevenstypen expliciet te converteren, bijvoorbeeld: laten we zeggen dat we de getallen 15 en 2 moeten delen, delen! 15/2=7. Het resultaat is hetzelfde als in de tabel. Maar als je kleine transformaties maakt, bijvoorbeeld: 15,0/2=7,5, bij deze deling is het getal 15 reëel, wat betekent dat het resultaat reëel zal zijn. Het getal 15 zelf is wiskundig gezien niet veranderd, omdat 15 = 15,0. Dezelfde techniek zou op twee getallen kunnen worden toegepast, het resultaat zou hetzelfde zijn, of het zou op twee getallen tegelijk kunnen worden toegepast, maar waarom, als een van de twee genoeg is.

Een andere manier om gegevenstypen expliciet te converteren is:

Float(15) / 2 // resultaat is 7,5, getal 15 wordt geconverteerd naar float-gegevenstype. double(15) / 2 // resultaat is 7,5 – hetzelfde!!!

C++ biedt ook een cast-operator van het unaire type:

Statische_cast(/*variabele of getal*/)

voorbeeld: static_cast (15)/2 het resultaat is 7,5
Voorbeeld met een variabele:

Int ret=15; statische_cast (ret)/2 //resultaat is 7,5

In het geval van een variabele moet u begrijpen dat in regel 2 de ret-variabele niet wordt geconverteerd naar het float-gegevenstype, maar dat er alleen een tijdelijke kopie van de ret-variabele met het float-gegevenstype wordt gemaakt. Laten we in de praktijk alle methoden voor expliciete en impliciete datatypeconversie bekijken.

// pryeobrazovanie.cpp: definieert het toegangspunt voor de consoletoepassing. #include "stdafx.h" #include #erbij betrekken naamruimte std gebruiken; int _tmain(int argc, _TCHAR* argv) ( int int_value15 = 15, int_value2 = 2; // declareer twee type variabelen int float float_waarde15 = 15, float_waarde2 = 2; // declareer twee float cout-variabelen<< fixed << setprecision(2) // определяем, при выводе чисел с плавающей точкой, два знака после запятой << "15 / 2 = " << int_value15 / int_value2 << endl //неявное преобразование типов данных << "15 / 2 = " << int_value15 / float_value2 << endl //неявное преобразование типов данных << "15 / 2 = " << float_value15 / int_value2 << endl //неявное преобразование типов данных << "15 / 2 = " << float_value15 / float_value2 << endl; //неявное преобразование типов данных cout << "15.0 / 2 = " << 15.0 / 2 << endl // явное преобразование типа данных, число 15.0 - число с плавающей точкой << "15 / 2.0 = " << 15 / 2.0 << endl; // явное преобразование типа данных, число 2.0 - число с плавающей точкой cout << "float(int_value15) / int_value2 = " << float(int_value15) / int_value2 << endl // явное преобразование типа данных << "15 / double(2) = " << 15 / double(2) << endl; // используя приводимый тип как функцию cout << "static_cast(15) / 2 = " << static_cast(15) / 2 << endl // унарная операция приведения типа << "static_cast(15) = " << static_cast(15) << endl // можно печатать различные символы из таблицы ASCII, << "static_cast(20) = " << static_cast(20) << endl; // в скобочках прописываем код символа, который находим в таблице ASCII system("pause"); return 0; }

IN lijn 5 aangesloten , deze bibliotheek is nodig om verschillende manipulators te gebruiken, in ons geval - vaste setprecisie() . IN lijn 10speciaal twee variabelen van het type gemaakt int , op dezelfde manier twee variabelen van type gemaakt binnen drijven lijn 11, zullen deze variabelen nodig zijn om hun waarden naar andere gegevenstypen om te zetten. INlijn 12na de exploitant uit en verschuif bewerkingen naar de uitvoerstroom << Er zijn twee manipulatoren fixed en setprecision() . Manipulator vast - dit is geen geparametriseerde manipulator, aangezien deze geen parameters accepteert en zonder haakjes is geschreven. Deze manipulator wordt gebruikt in combinatie met een geparametriseerde manipulator precisie instellen() en voert een vaste weergave van decimalen uit. Een manipulator precisie instellen() geeft het aantal decimalen weer, en het cijfer dat tussen haakjes staat. INlijnen 13, 14, 15, 16voorbeelden van impliciete gegevenstypeconversie worden getoond, deze voorbeelden zijn overgenomen uittafel 1. IN lijnen 17, 18toont een manier om gegevens expliciet te transformeren. De essentie van deze methode is dat je een komma en nul aan het gehele getal moet toevoegen. INlijnen 19, 20expliciete conversie wordt uitgevoerd door castable-typen als functies te gebruiken, waarbij u binnen de haakjes de waarde of variabele moet opgeven die moet worden geconverteerd. Lijnen 21, 22, 23 voeren een expliciete datatypeconversie uit met behulp van een unaire dataconversiebewerking. De haakjes geven de variabele of waarde aan die moet worden geconverteerd, en de tekens zijn omkaderd < > het gegevenstype waarnaar moet worden geconverteerd. Hieronder ziet u een voorbeeld van hoe het programma werkt (zie figuur 1).

Figuur 1 - Expliciete en impliciete conversie van C++-gegevenstypen

IN lijnen 22, 23 er wordt een unaire dataconversiebewerking uitgevoerd en de getallen 15 en 20 worden geconverteerd naar char. Dit datatype is nog niet bij je bekend, maar onthoud dat char een datatype is voor het opslaan van . Dus, van figuur 1 je kunt zien dat er aan het einde symbolen verschenen. Deze karakters werden verkregen door getallen om te zetten in char. De cijfers waren codes van . Als het dus nodig is om een ​​teken uit de ASCII-tabel uit te voeren, kan dit worden gedaan zoals weergegeven in lijnen 22, 23, terwijl alleen de vereiste code wordt vervangen.