Permalänk

C# Överlagrade Metoder

Hejsan, jag har precis börjat kursen programmering 1 och skulle vilja ha lite feedback på det jag gör. Sitter ensam när jag knappar och har ingen att bolla med så kan känna mig lite vilsen i mina uppgifter då jag inte alltid vet om jag är rätt ute eller ej, här är iaf en uppgift jag hållit på med ett bra tag nu och tillslut klarade (typ) kom gärna med feedback.

Uppgiften löd såhär:
Som det är nu ligger uträkningen från celsius till fahrenheit (fahrenheit = celsius * 9 / % + 32) på två ställen, en i varje överlagring (CelsiusToFahrenrheit & CelsiusToFahrenheit2)
Skapa istället en intern metod för denna uträkning. Metoden ska inte vara synlig utifrån (private) De båda överlagringarna ska använda denna interna metod. Kalla den CTF()

MITT SVAR:

class Program { static void Main(string[] args) { int grader = CelsiusToFahrenheit(100); double grader2 = CelsiusToFahrenheitF(100.3421); } //Metod som tar emot int temperatur static int CelsiusToFahrenheit(int celsius) { CTF(celsius); return celsius; } //Metod som tar emot decimal temperatur static double CelsiusToFahrenheitF(double celsius) { CTF(celsius); return celsius; } //Private metod som har hand om uträkningen för angivna gradantal. private static void CTF(object celsius) { if(celsius is int) { int man = Convert.ToInt32(celsius); int summa = man * 9/5+32; Console.WriteLine(summa); } else if (celsius is double) { double man1 = Convert.ToDouble(celsius); double summa = man1 * 9/5+32; Console.WriteLine(summa); } }

Lagt till [code]-taggar /Mod
Permalänk
Hedersmedlem

Hej, @Zero_Digits, och välkommen till Sweclockers!

När du lägger upp programkod på forumet är det bra om du lägger in texten [code] före och [/code] efter din kodsnutt. På det sättet så syns även indrag i koden på korrekt sätt. Det är svårt att läsa kod som saknar indrag, man tappar all struktur.

Jag har gjort detta åt dig den här gången, men nästa gång är det bra om du gör det själv.

Med vänlig hälsning,
pv2b (Moderator)

Permalänk
Hedersmedlem

Hej!

Du har nog inte riktigt lyckats lösa uppgiften som den är skriven.

För det första fungerar inte din kod alls. Metoderna CelsiusToFahrenheit och CelsiusToFahrenheitF anropar metoden CTF() på celsius, kastar bort svaret, och returnerar sedan värdet i celsius som matades in från början. (Edit: Tja, den "verkar" ju ut att funka om du bara kör koden direkt, men det är för att du kör Console.Writeline() inuti CTF...)

För det andra har du inte använt överlagrade metoder. En överlagrad metod är när du har två eller fler metoder med samma namn som tar olika sorters argument. Här har du istället två metoder med två olika namn.

För det tredje så har du krånglat till CTF() något rejält. Det jag hade gjort hade varit att istället skapa en metod CTF som tar en "double" som indata, och sedan skickar tillbaka en "double" som returvärde.

I metoden CelsiusToFahrenheit(double) hade jag då anropat denna metod rakt av och returnerat svaret. I metoden CelsiusToFahrenheit(int) hade jag då konverterat antalet grader till en double, anropat CTF, och redan konverterat tillbaka resultatet till en int. Att kolla vilken typ objektet är av och castning är ju bra att ha lärt sig, men det är egentligen inte alls syftet med uppgiften.

Lycka till i Programmering 1!

Permalänk

@pv2b: Hejsan och tack för snabbt svar. Jag har verkligen kämpat men inte fattat mycket av vad frågan igentligen ville att jag skulle göra. Så tack för ditt förtydligande. jag vet att min kod var helt sjukt ful att titta på men när jag satte in värderna i Int grader & int grader2 så kom faktiskt resultatet tillbaka i fahrenheit. Så något måste vart rätt haha.

Jag har lite problem med när man ska använda metod typen "void" och när det ska var en bestämd metod typ(int, double etc).

Det som krånglade till det i detta fallet är ju att man ska ha en private metod som ska kunna ta emot både en int och en double vilket jag tog som att den måste vara void, för annars måste den ju sättas som antingen int eller double och det hade ju blockerat förmågan att kunna sätta in två olika typer. Finns det något sätt att skapa en metod som kan ta in flera olika data typer fast inte behöva ta in mer än 1?

Bortsätt från det sättet du gjorde på såklart.

PS. Vad menar du med att jag kastar mitt värde av celsius?

Permalänk
Hedersmedlem
Skrivet av Zero_Digits:

@pv2b: Hejsan och tack för snabbt svar. Jag har verkligen kämpat men inte fattat mycket av vad frågan igentligen ville att jag skulle göra. Så tack för ditt förtydligande. jag vet att min kod var helt sjukt ful att titta på men när jag satte in värderna i Int grader & int grader2 så kom faktiskt resultatet tillbaka i fahrenheit. Så något måste vart rätt haha.

Detta beror på att du skriver ut resultaten i slutet av metoden CTF(). Men det resultatet skrivs bara ut på skärmen. Uppgiften vill ju att värdet ska komma i retur när du anropar funktionen. Console.Writeline() ska alltså stå i din main-metod någonstans efter att du kört dina CelsiusToFahrenheit-metoder.

Skrivet av Zero_Digits:

Jag har lite problem med när man ska använda metod typen "void" och när det ska var en bestämd metod typ(int, double etc).

Typen "void" betyder att metoden inte skickar tillbaka något returvärde. Ett exempel:

static void SayHello(string name) { Console.WriteLine("Hello, " + name + "!"); }

I det fallet så får inte den metod som anropar metoden SayHello() något i retur, utan den skriver bara ut på skärmen. Jämför detta med:

static void SayHello(string name) { string greeting = "Hello, " + name + "!"); return greeting; }

Exemplet ovan skriver inte ut något på skärmen, utan genererar istället en sträng med texten "Hello, Niklas!" (om du anropar SayHello("Niklas") alltså.)

void betyder alltså inte "okänd typ", utan den betyder "ingenting".

Om du ska beteckna "okänd typ" så är det närmaste du kommer i C# "object".

Skrivet av Zero_Digits:

Det som krånglade till det i detta fallet är ju att man ska ha en private metod som ska kunna ta emot både en int och en double vilket jag tog som att den måste vara void, för annars måste den ju sättas som antingen int eller double och det hade ju blockerat förmågan att kunna sätta in två olika typer. Finns det något sätt att skapa en metod som kan ta in flera olika data typer fast inte behöva ta in mer än 1?

Bortsätt från det sättet du gjorde på såklart.

Nej. Du ska inte ha en private metod som tar emot två olika datatyper. Du ska ha en privat metod CTF i "bakgrunden" som gör själva uträkningar, och dina publika metoder CelsiusToFahrenheit med olika typsignaturer (olika sorters värden den kan ta som argument) ska istället konvertera värdena så att de "passar in i" CTF.

Ett enkelt exempel på hur överlagring funkar:

using System; public class Program { public static void hej(double xxx) { Console.WriteLine("Det här är en double!"); } public static void hej(int xxx) { Console.WriteLine("Det här är en int!"); } public static void Main() { hej(1.0); // double hej(1); // int } }

https://dotnetfiddle.net/7XeCCp

Alltså, vilken metod som anropas beror på vilket slags värde du stoppar in!

Permalänk
Hedersmedlem
Skrivet av Zero_Digits:

PS. Vad menar du med att jag kastar mitt värde av celsius?

static int CelsiusToFahrenheit(int celsius) { CTF(celsius); return celsius; }

När du anropar CelsiusToFahrenheit(100) så händer följande:

1. Metoden CTF(celsius) anropas. Men du sparar aldrig returvärdet. (I och för sig såg jag ju sedan att metoden CTF returnerar "void", så här finns aldrig något returvärde att returnera.
2. Du returnerar sedan värdet i celsius, d.v.s. INTE konverterat!

Det är detta jag menade.

Permalänk

@pv2b:

Jag har börjat knappa om koden efter det du tipsade, men hur gör jag för att konvertera int celsius till double och sen tillbaka? Jag får bara felmeddelandet: Argument 1: cannot convert from 'int' to 'System.ReadOnlySpan<char>

class Program { static void Main(string[] args) { int graderH = CelsiusToFahrenheit(100); double graderD = CelsiusToFahrenheit(100.3421); } static int CelsiusToFahrenheit(int celsius) { } static double CelsiusToFahrenheit(double celsius) { CTF(celsius); return celsius; } private static double CTF(double celsius) { double fahrenheit = celsius * 9 / 5 + 32; return fahrenheit; } }

Permalänk

Ok jag tro jag har löst det nu. Ursäktar för min trötta hjärna. Har suttit med detta sen kl 10 imorse, det här med metoder har inte riktigt lossnar för mig. Hur ser detta ut?

Svar:

class Program { static void Main(string[] args) { int graderH = CelsiusToFahrenheit(100); double graderD = CelsiusToFahrenheit(100.3421); Console.WriteLine(graderD); Console.WriteLine(graderH); } static int CelsiusToFahrenheit(int celsius) { double grader = Convert.ToDouble(celsius); grader = CTF(celsius); int grader2 = Convert.ToInt32(grader); return grader2; } static double CelsiusToFahrenheit(double celsius) { double fahrneheit = CTF(celsius); return fahrneheit; } private static double CTF(double celsius) { double fahrenheit = celsius * 9 / 5 + 32; return fahrenheit; } }

Permalänk
Hedersmedlem

Ser mycket bättre ut! Finns några små stilgrejer men i allt väsentligt har du löst uppgiften som den är skriven!

Bra jobbat.

Skickades från m.sweclockers.com

Permalänk
Hedersmedlem

Hittade en liten grej som är fel, men programmet funkar ändå.

Se nedan:

static int CelsiusToFahrenheit(int celsius) { // Gör om int celsius till double grader double grader = Convert.ToDouble(celsius); // Men sedan använder vi aldrig grader, utan skickar in int celsius istället. Vilket gör raden ovan helt meningslös. Anledningen till att detta fungerar ändå är att C# är smart nog att konvertera mellan datatyper automatiskt när det funkar grader = CTF(celsius); // På samma sätt skulle du kunna skippa den explicita konverteringen här och bara köra return grader int grader2 = Convert.ToInt32(grader); return grader2; }

Skickades från m.sweclockers.com

Permalänk

@pv2b: Tack så mycket för din hjälp Du får gärna komma med all kritik du har, vill få så bra syntax som möjligt.

Kan du svara på varför det blir såhär?

public static int FahrenheitToCelsius(int celsius) { double fahrenheit = FTC(celsius); //Heltalet sätts in i metoden utan att man behöver konvertera data typ till double? int fahrenheit2 = Convert.ToInt32(fahrenheit); //Måste konvertera tillbaka till int även fast jag aldrig konverterade till double? return fahrenheit2; //fahrenheit2 returneras med det nya värdet }

Permalänk
Hedersmedlem
Skrivet av Zero_Digits:

@pv2b: Oj jag såg det nu med. Men kan du svara på varför det blir såhär?

Vi tar det rad för rad:

public static int FahrenheitToCelsius(int celsius) {

Du definierar att metoden tar in en int, och returnerar en int.

double fahrenheit = FTC(celsius); //Heltalet sätts in i metoden utan att man behöver konvertera data typ till double?

Exakt så! C# är smart nog att fatta att FTC vill ha en double, och konverterar automatiskt en int till en double utan att du behöver skriva detta explicit.

Detta kan förresten göras helt säkert utan dataförlust. En double kan representera alla möjliga tal som en int kan representera. (Men inte tvärtom! Se nedan.)

int fahrenheit2 = Convert.ToInt32(fahrenheit); //Måste konvertera tillbaka till int även fast jag aldrig konverterade till double? return fahrenheit2; //fahrenheit2 returneras med det nya värdet }

Du konverterade aldrig till double explicit, nej, men det som spelar roll är att FTC ger sitt resultat som en double. Därför "måste" det konverteras till int, även om det kan göras implicit.

Här kunde du bara ha skrivit "return fahrenheit" istället om du ville. På samma sätt kan C#-kompilatorn automatiskt konvertera en double till en int. Den vet ju att du vill ha en int tillbaka ur metoden (står längst upp i metodsignaturen).

Nu här nedan blir det överkurs.

Här finns faktiskt möjlighet att du förlorar lite data. Tänk på att en double kan representera många fler sorters värden än en int kan. Int kan bara representera heltal mellan -231 och 231 - 1. En double kan representera ett tal med decimaler, och även en mycket större räckvidd. Det är rent teoretiskt möjligt att du kanske skickar in 231 - 1 som invärde i celsius, och ditt svar i fahrenheit blir för stort för att få plats i en int.

En annan grej är att när du bara "konverterar" ett flyttal till en int så blir det inte en avrundning till närmaste heltal, utan istället "hugger man bara av" decimalerna. T.ex:

double hej = 1.99; int hopp = hej; // hej sätts till 1

Här kanske ett mer önskvärt resultat är att du avrundar till närmaste heltal. Detta kan du göra i C# med metoden Math.Round(Double). (Om du läser lite på den här dokumentationssidan så hittar du förresten lite mer exempel på överlagring, flera funktion med samma namn. Den du vill använda tar en Double som argument, och returnerar en Double.)

double hej = 1.99; int hopp = Math.Round(hej); // hej sätts till 2

Sista raden i din FahrenheitToCelsius skulle alltså kunna vara:

return Math.Round(fahrenheit);

I det fallet så är fahrenheit en double, vilket är precis vad Math.Round vill ha. Math.Round returnerar det avrundade svaret till närmaste heltal, men representerar fortfarande svaret i en double. Men implicit konverteras detta igen till ett heltal, genom att trunkera det avrundade värdet (vilket ju blir precis vad du vill i det läget.)

Genom att avrunda så kommer dina värden bli närmare verkligheten för heltal, istället för att konsekvent visa lite för låga värden.

Permalänk
Medlem
Skrivet av pv2b:

Här kunde du bara ha skrivit "return fahrenheit" istället om du ville. På samma sätt kan C#-kompilatorn automatiskt konvertera en double till en int. Den vet ju att du vill ha en int tillbaka ur metoden (står längst upp i metodsignaturen).

C# tillåter väl inte implicit konvertering från double till int? I alla fall enligt denna sida så kan double inte konverteras implicit till någon annan typ. Som du säger finns det annars risk att man förlorar information, och då brukar man normalt behöva göra en explicit cast för att tala om för kompilatorn att man verkligen vill utföra konverteringen.

Permalänk
Hedersmedlem
Skrivet av perost:

C# tillåter väl inte implicit konvertering från double till int? I alla fall enligt denna sida så kan double inte konverteras implicit till någon annan typ. Som du säger finns det annars risk att man förlorar information, och då brukar man normalt behöva göra en explicit cast för att tala om för kompilatorn att man verkligen vill utföra konverteringen.

Du har helt rätt! I C funkar det som jag beskrev, men i C# behövs en explicit konvertering.

Förmodligen just för att du aldrig tappar någon information i konvertering från int till double, men du kan göra det åt andra hållet.

Däremot kan man ju göra så här:

using System; public class Program { public static void Main() { double a = 1.99; int b = (int)a; int c = (int)Math.Round(a); Console.WriteLine("b = " + b); // skriver ut b = 1 Console.WriteLine("c = " + c); // skriver ut c = 2 } }

https://dotnetfiddle.net/GhiYw6

I det fallet så används en explicit "typecast" (där jag skriver (int)) för att konvertera värdet.

Permalänk

@pv2b: Hej igen! Mycket bra förklarat. Det var lite som @perost var inne på där att C# gav mig ett kompileringsfel när jag skulle returnera double variabeln utan att konvertera den till int först. Hur som helst borde ju C# kunna implicit konvertera talen åt båda hållen i detta fallet då själva metoden enbart tar emot Int typer som ska skickas igenom en ganska basic algoritm utan decimaler inblandat, den borde ju känna av att detta double värdet funkar som en int. Men men. Tack igen!

Permalänk
Medlem

@Zero_Digits: int kan som sagt konverteras förlustfritt till double, men inte tvärtom. Det handlar alltså inte om att C# inte kan göra det, utan om att C# kräver att du explicit talar om att du faktiskt vill utföra konverteringen även fast det innebär en förlust av information.

Det är alltså på det sättet för att undvika att du av misstag råkar konvertera double till int (lätt hänt i lite mer komplicerad kod). I t.ex. C är det däremot som pv2b säger tillåtet, eftersom C inte bara låter dig skjuta dig själv i foten utan glatt räcker över geväret

Din CTF-metod involverar förresten decimaler eftersom du utför division, 21°C är t.ex. 69.8°F. Men även om metoden alltid skulle returnera värden som kan tolkas förlustfritt som heltal så är det på det stora hela enklare att ha en regel som alltid gäller än att ha specialfall.

Permalänk
Medlem

Ska verkligen metoden som tar emot en int returnera en int? Då formeln multiplicerar med 1.8 (9 / 5) är det troligt att du får decimaler även vid konvertering av celsius i heltal. Att kasta bort dessa decimaler bara för att du anropat med ett heltal låter konstigt. (Uppgiften är iofs rätt konstig i helhet, då vi konstaterat att du inte ens behöver ha en metod som tar emot int iom implicit konvertering av int till double)

Visa signatur

Kom-pa-TI-bilitet