Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C#: Metodin kutsun välittäminen toiselle

AtskaFin [05.04.2019 19:04:16]

#

Tulipa tuossa koodatessa mieleen, seuraava kysymys: pystyykö kahden samannimisen metodin välillä tehdä kutsua :this() -kaltaisen koodipätkän kanssa niin, kuin konstruktorien ylikuormituksessa?

Yleensä kutsun samannimisiä metodeja vain seuraavalla tavalla:

public void RemoveAt(int index) { RemoveAt(index, 1); }

public void RemoveAt(int index, int count)
{
    if (index > arr.Length) throw new ArgumentOutOfRangeException();
    else
    {
        try
        {
            if (count != 1) count += 1;


            T[] newArr = new T[arr.Length - count];

            for (int i = 0; i < index; i++)
            {
                newArr[i] = arr[i];
            }

            for (int i = index; i <= newArr.Length - count; i++)
            {
                newArr[i] = arr[i + count];
            }

            arr = newArr;
        }
        catch (OverflowException)
        {
            Console.WriteLine("Index was out of array...");
        }
    }
}

Eihän tuossa siis yhtään mitään vikaa ole, mutta tulipa tällainen asia mieleen.

Lisäys:

löysin netistä jutun tästä, se onnistuu seuraavanlaisesti:

public void RemoveAt(int index) => RemoveAt(index, 1);

Metabolix [06.04.2019 01:33:13]

#

Voisit käyttää myös parametrin oletusarvoa, jolloin yksi metodi riittää.

public void RemoveAt(int index, int count = 1)

Koodissasi on epäloogista, että tietyissä virhetilanteissa tulostat virheviestin mutta toisissa heität poikkeuksen. Yleensä metodin ei pitäisi tulostaa mitään, jos metodin tarkoitus ei ole nimenomaan tulostaminen.

Täysin ennakoitavat virhetilanteet olisi myös fiksua tunnistaa jo etukäteen if-lauseella try-lohkon sijaan. Esimerkiksi tässä on aika helppoa tarkastaa, että lukumäärä ei ole negatiivinen ja että alku- ja loppuindeksit ovat kelvolliset.

The Alchemist [08.04.2019 18:53:05]

#

Metabolix kirjoitti:

Täysin ennakoitavat virhetilanteet olisi myös fiksua tunnistaa jo etukäteen if-lauseella try-lohkon sijaan. Esimerkiksi tässä on aika helppoa tarkastaa, että lukumäärä ei ole negatiivinen ja että alku- ja loppuindeksit ovat kelvolliset.

Itse olen kyllä vähän sitä mieltä, että vähentää ns. turhaa koodia ja antaa poikkeusten lennellä. Jollain tavallahan noistakin virheistä on ilmoitettava vaikka niille koodaisi itse tarkistukset? Eli varmaankin poikkeusta heittämällä? Koodaisin omat tarkistukset vain niissä tapauksissa, kun kyseinen virhetilanne johtaisi automaattisesti sovelluksen kaatumiseen poikkeuksen heittämisen sijaan.

Jaska [13.04.2019 15:11:25]

#

If-elsellä voidaan rajoittaa, että vain joku koodinpätkä suoritetaan. Try-osa suoritetaan aina. Tilanteesta riippuu, kumpaa kannattaa käyttää.

Grez [13.04.2019 15:46:16]

#

Olen periaatteessa Alchemistin kanssa samaa mieltä että läheskään joka paikassa ei kannata itse koittaa käsitellä poikkeuksia. Tällaisessa taulukkoa muokkaavassa funktiossa on kuitenkin perusteltua tarkistaa että annetut muuttujat on mahdollisia ennen kuin muokataan taulukkoa.

Eli kuiten Metabolix sanoikin niin tarkistaa tuon toisenkin potentiaalisen virheen aiheuttajan voisi tarkistaa jo alussa. Sen jälkeen ei enää olekaan tarvetta try catchille ja tietenkään konsoliin ei pitäisi tuollaisessa funktiossa kirjoittaa.

Kaikkein eniten tuossa tosin ihmetyttää täysin epäloogiselta vaikuttava

AtskaFin kirjoitti:

if (count != 1) count += 1;

Sanoisin jopa että tuossa on bugi, jonka voisi korjata poistamalla ko. rivin tai muuttamalla funktion nimeksi esimerkiksi WeirdAndCumbersomeRemoveAt

Jaska kirjoitti:

If-elsellä voidaan rajoittaa, että vain joku koodinpätkä suoritetaan. Try-osa suoritetaan aina. Tilanteesta riippuu, kumpaa kannattaa käyttää.

Ei try-osaakaan suoriteta kuin siihen asti että ensimmäisen kerran lentää poikkeus.

Itse sanoisin, että If:llä voidaan estää suorittamasta edes osaa koodista, kun odotettavissa on virhetilanne.

The Alchemist [14.04.2019 05:45:06]

#

Grez kirjoitti:

Olen periaatteessa Alchemistin kanssa samaa mieltä että läheskään joka paikassa ei kannata itse koittaa käsitellä poikkeuksia. Tällaisessa taulukkoa muokkaavassa funktiossa on kuitenkin perusteltua tarkistaa että annetut muuttujat on mahdollisia ennen kuin muokataan taulukkoa.

Tarkoitit varmaan, että on perusteltua korjata muuttujien arvot "oikeiksi" tai vaihtoehtoisesti olla tekemättä mitään?

Aika useinhan taulukoita käsittelevät funktiot on määritelty niin, että jos vaikka käsketään poistaa viisi alkiota mutta taulukossa on vain neljä alkiota, niin funktio poistaa kyseiset neljä alkiota ja suoritus päättyy onnistuneesti virhetilanteen sijaan. Tai että jos yritetään poistaa "miinus yksi" alkiota, niin sekään ei välttämättä ole virhe, mutta mitään ei myöskään poisteta.

En kyllä ole itse niin varma, että vaivautuisinko tällöinkään tekemään hirveästi indeksitarkistuksia vai jättäisinkö funktion sisällä olevan try-catchin paikoilleen nappaamaan virheellisistä arvoista johtuvat poikkeukset, jotka sitten ignorettaisin hiljaisesti. Se on varmaan perusteltava sitten analysoimalla suorituskykyä, että onko try-catchin käyttö paljon huonompi vaihtoehto kuin manuaaliset tarkistukset ennen taulukkoon koskemista.

Toisaalta negatiivisen indeksin tarjoaminen parametrina kielii siitä, että se osa koodista, missä indeksi laskettiin ja päädyttiin negatiiviseen arvoon, on itsessään rikki, eli jos tämä taulukkoa käsittelevä funkkari heittää poikkeuksen, niin se bugi tulee ilmi.

(Verrattuna siihen, että liian suuren lukumäärän tarjoaminen on vain kätevää ohjelmointia, koska lopputuloksen kannalta on usein merkityksetöntä, onko listalla vähemmän alkioita kuin siitä halutaan poistaa, sillä jäljelle jäävien alkioiden määrä on kuitenkin sama.)

Lisäys:

Sitten vielä se, että heitettävä poikkeuskin tulee valita järkevästi, jottei funktiota kutsuessa tarvitse kirjoitella mahdottomasti erilaisia catch-ehtoja. Jos taulukkoa käsiteltäessä kielen vakio-ominaisuus on heittää OverflowException, niin en pidä järkevänä, että omassa koodissa päättääkin heittää jotain muuta.

Ensinnäkin muut koodarit voivat intuitiivisesti olettaa, että koska käsitellään taulukkoa, niin funktio käyttäytyy samoin kuin muutkin taulukoita käsittelevät funktiot.

Toisekseen voi käydä niin, että jossain yllättävässä tilanteessa et napannutkaan ennalta virhettä ja kielen oma virheenkäsittelijä heittää sen OverflowExceptionin, ja nyt ollaan taas siinä tilanteessa, että joskus lentää OverflowException ja joskus ArgumentOutOfRangeException, vaikka virhetilanteet näyttävät funktiota kutsuvalle koodarille hyvin samankaltaisilta.

Metabolix [15.04.2019 12:57:58]

#

Sinänsä tässä metodissa voisi tosiaan poistaa pyydetyn alueen soveltuvin osin ilman virhettä. Kuitenkin silloin pitää olla erityisen tarkka, että negatiiviset ym. oudot syötteet toimivat oikein. Johtaako negatiivinen määrä poistoon takaperin, lisäykseen vai tyhjään toimenpiteeseen?

Myös valmiiden poikkeusten hyödyntäminen toimii, mutta tilanteesta riippuen voi mennä paljonkin aikaa hukkaan: jos vaikka tehtäisiin monen HTTP-pyynnön tai tietokantakyselyn sarjaa ja viimeisen syöte olisi väärän muotoinen, voisi käyttäjää harmittaa. Lisäksi pitäisi ehkä perua jo tehtyjä muutoksia, missä on taas uusi virheen mahdollisuus.

Perussääntönä kannattaa pitää, että kaikki mahdolliset syötteet jotenkin huomioidaan metodissa, onpa ratkaisuna tarkastus ja poikkeus tai tarkkaan harkittu tulos. Tästä voi sitten poiketa sisäisissä metodeissa, jos on täysin selvää, millä syötteillä niitä käytetään. Silloinkin voi harkita metodin nimeämistä niin, että reunaehdot käyvät siitä ilmi.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta