GPT 4 tentafrågor - Generics Flashcards
Vilket påstående är sant om generiska typer i programmering?
- Generiska typer tillåter en klass eller metod att operera på objekt av olika typer samtidigt.
- Generiska typer ökar behovet av kodåteranvändning eftersom du måste skriva en ny klass för varje datatyp.
- Generiska typer är mindre effektiva eftersom de kräver mer körtid för typkontroll.
Svar: 1
Generic types tillåter en klass eller metod att operera på objekt av olika typer samtidigt.
Användning av generiska supertyper
Hur används generiska supertyper mest effektivt?
- För att skapa hierarkier av typberoende kod, vilket minskar redundans.
- För att begränsa polymorfism och förhindra att generiska typer används i olika klasser.
- Att använda generiska supertyper är ett tecken på dålig kodstruktur och bör undvikas helt.
Svar: 1
För att skapa hierarkier av typberoende kod, vilket minskar redundans.
Vad är syftet med generics i programmering?
- Att möjliggöra för kod att hantera specifika datatyper
- Att skapa större och mer komplex kod
- Att möjliggöra för kod att arbeta med olika datatyper utan att förlora den statiska typsäkerheten
Förklaring: Det korrekta svaret är alternativ 3.
Generics (allmänna typer) tillåter kod att arbeta med vilken datatyp som helst samtidigt som man behåller statisk typsäkerhet, vilket gör att samma kodblock kan återanvändas för olika typer och minska upprepning.
Vilket påstående är sant om generics?
- Generics tvingar dig att skriva ny implementation för varje ny datatyp.
- Generics kan inte använda grundläggande datatyper som int, string etc.
- Med generics kan en metod eller klass arbeta med objekt av en godtycklig datatyp.
Förklaring: Alternativ 3 är korrekt.
Genom att använda generics kan utvecklare skriva metoder eller skapa klasser som fungerar med vilken datatyp som helst, vilket ökar återanvändbarheten och typsäkerheten i koden utan att skapa en ny metod eller klassimplementation för varje datatyp.
Hur skapar du en generisk lista som kan innehålla element av vilken typ som helst i C#?
1. List<T> myList = new List<T>(); 2. List[] myList = new List; 3. List myList = new List();
Förklaring: Alternativ 1 är rätt.
List<T> är syntaxen för att deklarera en generisk lista i C#. "T" är en platshållare som representerar en datatyp, och den specifika datatypen anges när en lista skapas, till exempel new List<int>() eller new List<string>().</string></int></T>
Vilket är ett scenario där generics är mest användbara?
- När du vill ha olika beteenden baserade på datatyper
- När kodens beteende inte beror på datatyper
- När varje datatyp kräver en unik metod
Förklaring: Alternativ 2 är korrekt.
Generics är mest användbara när beteendet för kod, såsom en metod eller en klass, är konsekvent oavsett vilken datatyp som används. Detta möjliggör återanvändning av kod och behåller typsäkerheten utan att behöva skriva ny kod för varje specifik datatyp.
Varför är användningen av en icke-generisk ObjectPair-klass inte compile-type safe?
- Eftersom ObjectPair-klassen tillåter alla datatyper, kan det leda till oväntade körtidsfel.
- ObjectPair kan inte hålla två objekt samtidigt.
- ObjectPair-klassen kastar undantag vid kompilering.
Svar: Alternativ 1
Förklaring: ObjectPair använder object, vilket är grundklassen för alla datatyper i C#. Detta innebär att du kan lagra vilken typ som helst där, men kompilatorn kan inte garantera typsäkerheten för de objekt som lagras. Som ett resultat, vid åtkomst måste objekten castas till deras faktiska typ, och felaktig castning kommer endast att identifieras under körningstid, vilket leder till potentiella körtidsfel.
Vilken är en direkt fördel med att använda en generisk Pair<T>-klass över en icke-generisk ObjectPair-klass?</T>
- Större lagringsutrymme.
- Minskat behov av typkonverteringar och förbättrad typsäkerhet.
- Automatiska säkerhetskopior av data.
Svar: Alternativ 2
Förklaring: Generiska klasser som Pair<T> bibehåller typinformation. Det innebär att du inte behöver göra downcasting från object till den faktiska datatypen, eftersom T behåller den specifika typen. Detta förbättrar typsäkerheten eftersom kompilatorn vet vilken typ av objekt som är lagrade och kan upptäcka fel vid compile-time.</T>
Vad är resultatet av att använda generics i Pair<T>-klassen jämfört med att ha separata DiceRollPair och CardPair klasser?</T>
- Ökad kodupprepning och minskad flexibilitet.
- Förbättrad kodunderhållbarhet genom att minska redundans och säkerställa typsäkerhet.
- Automatiserad felkontroll vid kompileringstid.
Svar: Alternativ 2
Förklaring: Genom att använda Pair<T>, behöver du inte skapa separata, nästan identiska klasser för olika datatyper. Det minskar mängden redundant kod och gör koden enklare att underhålla. Typsäkerheten garanteras eftersom Pair<T> kommer att insistera på att båda objekten är av samma förutbestämda typ T.</T></T>
Vilken utmaning kan uppstå när man använder en generisk klass som Pair<T> i ett större projekt?</T>
- Det kan vara svårare att skriva och förstå kod, särskilt om generiska typer blir djupt nästlade.
- Generics kan orsaka att applikationen körs långsammare.
- De kan förhindra användningen av vissa inbyggda metoder i C#.
Svar: Alternativ 1
Förklaring: Generics kan göra koden mer komplex, särskilt när du börjar nästla dem (t.ex., Pair<Pair<T>>). Det kan vara en utmaning att förstå och underhålla sådan kod, särskilt för någon som inte är bekant med generics. Denna komplexitet ökar med skalan på projektet.</T>
Varför är det fördelaktigt att använda List<T> istället för vanliga arrayer i samband med generics? 1. List<T> ger mer dynamisk minneshantering, vilket gör det enklare att lägga till eller ta bort element. 2. List<T> har snabbare åtkomsttider än arrayer. 3. Arrayer i C# kan inte användas med generics.
Svar: Alternativ 1
Förklaring: List<T> är en dynamisk datastruktur, vilket innebär att du lätt kan lägga till och ta bort element utan att behöva hantera arrayens storlek manuellt. Detta gör koden renare och enklare att underhålla, och det utnyttjar fördelarna med generics för typsäkerhet och minskad kodupprepning.</T>
Förståelse av Generiska Interface
interface ISequence<T> { T Next(); // ... andra medlemsdefinitioner ... }
Vilket av följande påståenden är korrekt gällande
ISequence<T>?
ISequence<T> är en öppen typ eftersom T inte är specificerad.
ISequence<T> kan direkt instansieras med new ISequence<int>();
ISequence<T> måste ha en metod som accepterar en parameter av typen T.
Svar 1: ISequence<T> är en öppen typ eftersom T inte är specificerad. Förklaring: ISequence<T> definierar ett generiskt gränssnitt där T är en platshållare för en framtida specifik typ. Detta gör ISequence<T> till en öppen typ. Du kan inte instansiera ISequence<T> direkt eftersom det är ett gränssnitt, och gränssnitt kan inte instansieras direkt. Dessutom säger inget i definitionen av ISequence<T> att en metod måste acceptera en parameter av typen T, så det sista påståendet är inte heller sant.
Arv och Subtyper
public class StepSequence : ISequence<int> { // ... kod här ... }
-
Vilket av följande påståenden är sant angående StepSequence? 1. StepSequence är en sluten typ som är en subtyp av en sluten konstruktion av ISequence<T>. 2. StepSequence kan ärva från flera versioner av ISequence<T> med olika typer för T. 3. StepSequence är en öppen typ och kan implementera metoder som returnerar vilken typ som helst.
Korrekt svar: 1
StepSequence är en sluten typ som är en subtyp av en sluten konstruktion av ISequence<T>. Förklaring: När StepSequence implementerar ISequence<int>, specificerar den T som int, vilket gör den till en sluten typ (en typ där alla generiska parametrar har angetts). Detta gör också StepSequence till en subtyp av en sluten konstruktion av ISequence<T> där T är int. Den kan inte ärva från flera versioner av ISequence<T> med olika typer för T eftersom en klass inte kan ha flera basversioner av samma generiska gränssnitt med olika typargument. Det sista påståendet är inte relevant eftersom StepSequence inte är en öppen typ och den måste följa kontrakten definierade i ISequence<int>.
Begränsningar och Typhierarkier
public class Cycle<T> : IFiniteSequence<T> { // ... kod här ... }
Och följande kod som använder klassen:
Cycle<string> myCycle = new Cycle<string>(/* parametrar här */);
-
Baserat på kodanvändningen ovan, vilket av följande påståenden är sant? 1. Cycle<T> är en subtyp av IFiniteSequence<T> för alla T, och myCycle är en instans av en sluten konstruktion av Cycle<T>. 2. Cycle<string> skapar en ny klass vid kompileringstid med alla instanser av T ersatta med string. 3. Cycle<T> är sin egen supertyp och kan därför inte interagera med IFiniteSequence<T>-metoder.
Korrekt svar: 1
Cycle<T> är en subtyp av IFiniteSequence<T> för alla T, och myCycle är en instans av en sluten konstruktion av Cycle<T>.</T></T></T>
Förklaring:
Cycle<T> är en generisk klass och är en subtyp av IFiniteSequence<T>. För varje specifik T, Cycle<T> är en subtyp av IFiniteSequence<T>, vilket innebär att för alla T uppfyller den kontraktet som anges av IFiniteSequence<T>. När vi skapar en instans av Cycle<string>, som med myCycle, har vi en sluten konstruktion av Cycle<T> där T är string. Påståendet om att Cycle<string> skapar en ny klass vid kompileringstid är en missuppfattning av hur generiska typer fungerar i C#; kompilatorn skapar inte nya klasser för varje instansiering av en generisk klass. Det sista påståendet är inkorrekt eftersom Cycle<T> inte är sin egen supertyp och korrekt interagerar med metoder definierade i IFiniteSequence<T>.</T></T></string></T></string></T></T></T></T></T>