Kultainen koodi

.NET-osaajan ajatuksia paremmasta koodailusta

Archive for the tag “C#”

Code Wars, mahdollisuus oppia

Tutustuin codewarsiin työkaverini suosituksesta yhtenä syksyisenä päivänä. Hän löysi koodiharjoitussivuston, jossa editoria ja testejä voi ajaa selaimen kautta. Toisin kuin exersim.io tai vastaavissa palveluissa, codewarsilla harjoitteleminen onnistuu ilman kehitysympäristöä.

Harjoitusten tekeminen codewarsissa käy helposti. Harjoitusta kutsutaan nimellä kata.

codewars_kata

Kata eli harjoitus codewars.com:ssa.

 

Harjoituksen tehtävänanto selviää ruudun vasemmalta puolelta. Koodi kirjoitetaan oikeassa yläkulmassa näkyvään koodinäkymään. Kirjoitettu koodi ajetaan ”paikallisia” testejä vastaan Run Examples -painikkeella. Ne löytyvät Example Tests -otsikon alta. Näitä testejä voi myös muokata omien mieltymysten mukaan.

Lopullinen testi ratkaisulle tehdään ajamalla koodi Attempt-painikkeella. Ratkaisun toimivuus testataan yksikkötesteillä, joita ei näytetä käyttäjälle. Vain testien tulos näytetään. Toisinaan testien nimestä voi päätellä mikä testi epäonnistui. Järjestelmä sallii myös satunnaistettujen testien ajamisen, jolloin tehtävän luojan ei tarvitse kirjoittaa kaikkia testitapauksia käsin.

Ratkaistuasi tehtävän, saat vaikeusasteen mukaan tietyn määrän pisteitä. Helpoimmat testit saa ratkaistua muutamassa minuutissa, vaikeampien ratkaiseminen kestää tunteja.

Ratkaistuasi tehtävän, näet muiden vastaukset ja näistä oppii. Vastauksista voi merkata omasta mielestä parhaan ja nokkelan vastauksen. Vastauksista näkee kuinka paljon ohjelmoijien ongelmanratkaisukyky ja API-tuntemus vaihtelee.

codewars_stats

Stats-sivu kertoo mistä olet saanut pisteitä.

 

Olen kerännyt suurimman osan pisteistäni tekemällä harjoituksia. Pisteiden hankkimiseen käytetyt kielet näkyvät oikeasta laidasta ja prosenttiosuus kertoo kuinka paljon pisteitä on kerätty ennen seuraavaa tasoa.

Pisteet päivittyvät muutaman tunnin välein, kun palvelin ajaa ajastetusti pisteiden päivistyskriptit. Itsekin ihmettelin aluksi miksi pisteet päivittyvät viiveellä.

Jos teet vain harjoituksia, pisteillä ei ole merkitystä. Halutessasi voit kirjoittaa harjoituksia muiden ratkaistavaksi tai kääntää niitä kieleltä toiselle. Tällöin korkeampi pistemäärä sallii kevyemmän validointiprosessin ennen kuin kirjoittamasi harjoitus julkaistaan.

Yhteisöllisyyttä yritetään lisätä klaanien avulla. Käyttäjän tiedoissa voi antaa itselleen klaanin. Se on vain merkkijono. Kaikki jotka kirjoittavat saman merkkijonon, tulevat samaan klaaniin.

codewars_klaanit

Klaanit

 

Klaanijärjestelmä ei ehkä ole täydellinen, koska vaihdettuani klaanin, näen edelleen kaikki vanhan klaanini jäsenet.

Codewars on ehdottomasti paras palvelu ohjelmointiharjoitusten tekemiseen. Sen avulla voi ylläpitää kielen osaamista tai opetella uutta kieltä. Toki harjoitusten avulla oppii erityisesti kielen käyttöä, ei niihin liittyvien frameworkkien käyttöä.

Suosittelen kokeilemaan codewarsia, sen avulla voit löytää palon vanhaan rakkaaseen kieleen tai kehittää osaamistasi nykyisen kielen kanssa.

 

 

 

Windows Forms lokalisointi, Satellite Assemblies

Windows Forms -lokalisointi eli kieliversioiden tarjoaminen teksteille ei käy käden käänteessä. Teknisesti asia hoidetaan yksinkertaisesti. Luodaan yksi resurssitiedosto jokaiselle tarvittavalle kielelle ja merkkijonojen käännökset sijoitetaan näihin tiedostoihin. Uudemmilla tekniikoilla, kuten WPF, tämän voi automatisoida hyvin pitkälle esimerkiksi ReSharperilla.

Demoissa käytetty Microsoftin ”automaattinen” kieliversiointi luo jokaiselle lomakkeelle ja UserControllille omat resurssitiedostot. Esimerkiksi kymmenen formin ja viiden UserControllin projektissa tällöin kahdelle kieliversiolle tulisi kolmekymmentä resurssitiedostoa, joissa sama teksti toistuisi useaan kertaan. Ok- tai Peruuta-tekstit pitäisi kääntää jokaisen komponentin kohdalla erikseen ja muistaa tehdä muutokset jokaiseen resurssitiedostoon.

Windows forms -lokalisointi toimii näin:
1. Luodaan resurssitiedostot käytetyille kielille
2. Luodaan sovelluskohtainen ResourceManager
3. Asetetaan lomake tai UserControl lokalisoitavaksi
4. Tehdään lokalisointi koodin puolella
5. Luodaan lokalisoitavat tekstit resurssitiedostoihin
ja
6. Luodaan paikka, jossa voi vaihtaa kieliasetusta

Vaiheet 1 ja 2 tehtään kerran. Vaiheita 3-5 toistetaan jokaisen lokalisoitavan lomakkeen ja UserControllin kohdalla. Sovelluksesta riippuen, kieliversion vaihtaminen sijoitetaan sovelluksen mukaisesti joko aina nähtäville tai kertavalinnaksi.

Kieliversioitu testilomake

Yksinkertainen lomake Satellite Assembly -lokalisointia varten.

1. Luodaan resurssitiedostot käytetyille kielille

Luo projektiin Resources-kansio. Lisää sinne resurssitiedostot. Geneerinen en-valinta sopii hyvin Suomalaiseen makuun, koska meillä ei yleensä tehdä suurta eroa Amerikan- ja Britannianenglannin välille.

Luo resurssitiedostot

Luo resurssitiedostot

2. Luodaan sovelluskohtainen ResourceManager

Luo päälomakkeelle tai sovelluksen avaavaan program-kohtaan globaali ResourceManager.

private ResourceManager _resourceManager = null;

Initialinnin yhteydessä aseta nykyinen kulttuuri, tässä tapauksessa Suomi ja sen lisäksi viittaus resurssitiedostojen sijaintiin.

Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
_resourceManager = new ResourceManager("WFSatelliteAssembly.Resources.WFSatelliteAssembly", 
                                       Assembly.GetExecutingAssembly());

Globaalin resurssienhallitsijan sijaan voit luoda myös aina uuden, jos siltä tuntuu. Tällöin pitää huolehtia resurssitiedostojen löytymisestä, varsinkin jos yritetään viitata niihin toisesta projektista käsin. Useampaa projektia käytettäessä globaali olio tuntui kätevämmältä.

3. Asetetaan lomake tai UserControl lokalisoitavaksi

Valitse haluttu luokka ja muuta se lokalisoitavaksi.

Laita lokalisointi päälle

Laita lokalisointi päälle

4. Tehdään lokalisointi koodin puolella

Konstruktoriin, heti komponenttien initialisoinnin jälkeen aseta kieliversioidut tekstit.

InitializeComponent(); // Visual Studion luoma metodi
UpdateUiControls();

Itse päivitysmetodi

private void UpdateUiControls()
{
    try
    {
        if (_resourceManager != null)
        {
            Text = _resourceManager.GetString("Lomakkeen otsikko");
            uiLabelFirst.Text = _resourceManager.GetString("Eka teksti");
            uiLabel1.Text = _resourceManager.GetString("Toka teksti");
            uiLabel3.Text = _resourceManager.GetString("Kolmas teksti");
            uiLabel4.Text = _resourceManager.GetString("Valitse kieli");
            uiButton1.Text = _resourceManager.GetString("Peruuta");
            uiButtonTemput.Text = _resourceManager.GetString("Tee temput");
        }
    }
    catch (System.Exception e)
    {
        MessageBox.Show(e.Message);
    }
}

5. Luodaan lokalisoitavat tekstit resurssitiedostoihin

UpdateUiControls-metodissa annetaan avain, jonka perusteella haetaan lokalisoitu teksti. Esimerkiksi lomakkeen otsikko haetaan avaimella ”Lomakkeen otsikko” ja sen arvo suomeksi on ”Monikielisyys”. Jos kielen vaihtaa englanniksi, otsikon teksti muuttuu arvoon ”Satellite assembly test”.

Suomenkielinen lokalisointi

Suomenkieliset tekstit

Englanninkielinen lokalisointi

Englanninkieliset tekstit

6. Luodaan paikka, jossa voi vaihtaa kieliasetusta

Kielen valinta voidaan tehdä RadioButtonilla seuraavasti:

private void uiRadioButton_Click(object sender, Resco.UIElements.UIMouseEventArgs e)
{
    UIRadioButton radioButton = sender as UIRadioButton;
    string culture = string.Empty;
    if (radioButton == null) return;

    switch (radioButton.Text)
    {
        case "Suomi":
            culture = "fi-FI";
            break;
        case "English":
            culture = "en-GB";
            break;
    }

    // This is used for the language of the user interface
    Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture);
    // This is used with formatting and sort options (e.g. number and date formats)
    // e.g. a float value 2.352 will be 2,3.52 if CurrentCulture is set to de-DE
    Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(culture);
}

Näillä ohjeilla voi luoda kieliversioinnin Windows Forms -sovellukselle.

Katso myös

Bittivektorin tallentaminen integerinä

Bittivektori tallentaa kätevästi useamman muuttujan arvot yhteen muuttujaan. Aivan fantastinen keksintö. Se perustuu bitteihin. Luvut voidaan ilmaista nollina ja ykkösinä. Saman tiedon voi tallentaa merkkijonona ”00100101” tai lukuna. Luku mahtuu pienempään tilaan, jos data siirretään jonkinlaisen xml-wrapperin kautta. Tällöin yksi muuttuja vie huomattavasti vähemmän tilaa kuin usea boolean arvo.

Bittioperaatiot C#-kielellä

.NET-kielen bittioperaatiot ovat:

operaatio operattori
JA &
TAI |
XOR ^
EI ~

Pari käytännön esimerkkiä

Klassinen esimerkki löytyy yhteyden muodostuksesta. Päätelaitetta kätellessä voidaan kertoa muutama yhteyteen liittyvä tieto. Aikanaan myös datan koodaustyyli.

Bit Bit Value Meaning (1) Meaning (0)
7 128 Ready Off-Line
6 64 Connected Not Connected
5 32 Carrier Present Carrier Absent
4 16 Log Data Do Not Log Data
3 8 Auto Answer Mode Manual Answer Mode
2 4 Echo Commands Do Not Echo Commands
1 2 Use 8 Data Bits Use 7 Data Bits
0 1 Use Odd Parity Use Even Parity

Toinen tapaus voi olla käyttäjätiedot ja asetukset. Esimerkiksi sukupuoli, onko admin, jne. Mikäli asetuksissa käyttöliittymälle on valittavana erilaisia tyylejä, niin tyylivalinnat voi tallentaa bittivektoriin.

Bittivektoria voi käyttää valittujen viikonpäivien tallentamiseen. Mitkä tahansa päivät voidaan valita ja tallentaa tieto yhteen int-muuttujaan. Viikonpäiviä voi käyttää esimerkiksi herätyskello-toiminnossa. Sen voi laittaa soimaan tiettyinä viikonpäivinä. Sähköpostimuistutuksen tekemättömistä töistä voi lähettää tiettyinä viikonpäivinä (ma, ke, pe). Toistuvalle kalenteritapahtumalle voi määrätä halutut viikonpäivät.

päivä arvo
Maanantai 1
Tiistai 2
Keskiviikko 4
Torstai 8
Perjantai 16
Lauantai 32
Sunnuntai 64

Tyypillisesti käyttäjä valitsee käyttöliittymästä muutaman valinnan (CheckBox).

Valitut päivät

Valitut päivät

Valitut viikonpäivät saadaan tallennettua yhteen muuttujaan tai-operaattorin avulla.

int valitutPäivät = 0;

if (Maanantai.IsChecked != null && Maanantai.IsChecked.Value) 
    valitutPäivät = (int)Viikonpäivä.Maanantai;
if (Tiistai.IsChecked != null && Tiistai.IsChecked.Value) 
    valitutPäivät = (int)Viikonpäivä.Tiistai | valitutPäivät;
if (Keskiviikko.IsChecked != null && Keskiviikko.IsChecked.Value)
    valitutPäivät = (int)Viikonpäivä.Keskiviikko | valitutPäivät;
if (Torstai.IsChecked != null && Torstai.IsChecked.Value)
    valitutPäivät = (int)Viikonpäivä.Torstai | valitutPäivät;
if (Perjantai.IsChecked != null && Perjantai.IsChecked.Value)
    valitutPäivät = (int)Viikonpäivä.Perjantai | valitutPäivät;
if (Lauantai.IsChecked != null && Lauantai.IsChecked.Value)
    valitutPäivät = (int)Viikonpäivä.Lauantai | valitutPäivät;
if (Sunnuntai.IsChecked != null && Sunnuntai.IsChecked.Value)
    valitutPäivät = (int)Viikonpäivä.Sunnuntai | valitutPäivät;

Tässä esimerkissä käytetään viikonpäiville seuraavaa enumia

public enum Viikonpäivä
{
    Maanantai = 1,
    Tiistai = 2,
    Keskiviikko = 4,
    Torstai = 8,
    Perjantai = 16,
    Lauantai = 32,
    Sunnuntai = 64
}

Päivämäärän valinta tarkistetaan haetaan muuttujasta ja-operaattorin avulla ja asetetaan CheckBoxeihin

int valitutPäivät = 45; // ma, ke, to ja la

if ((valitutPäivät & (int)Viikonpäivä.Maanantai) != 0)
    Maanantai.IsChecked = true;
if ((valitutPäivät & (int)Viikonpäivä.Tiistai) != 0)
    Tiistai.IsChecked = true;
if ((valitutPäivät & (int)Viikonpäivä.Keskiviikko) != 0)
    Keskiviikko.IsChecked = true;
if ((valitutPäivät & (int)Viikonpäivä.Torstai) != 0)
    Torstai.IsChecked = true;
if ((valitutPäivät & (int)Viikonpäivä.Perjantai) != 0)
    Perjantai.IsChecked = true;
if ((valitutPäivät & (int)Viikonpäivä.Lauantai) != 0)
    Lauantai.IsChecked = true;
if ((valitutPäivät & (int)Viikonpäivä.Sunnuntai) != 0)
    Sunnuntai.IsChecked = true;

Mielestäni yhden muuttujan käyttäminen usean boolean muuttujan sijaan säästää tilaa, nopeuttaa tiedonsiirtoa ja joissain tapauksissa selkiyttää koodia. Tosin kielen toimintaa ja rakennetta pitää tuntea hieman enemmän. Toinen vaihtoehto tässä tapauksessa olisi käyttää seitsemään boolean muuttujaa ja sijoittaa tieto niiden kautta.

Mikäli kaikki tämä tapahtuu sovelluksen sisäisesti, niin toteutustavalla ei ole suurta merkitystä. Jos kuitenkin joudutaan siirtämään tietoa netin ylitse, niin asialla on merkitystä. Sovelluksen toiminnan kannalta hitain operaatio on tiedon siirtäminen netin ylitse. Seuraavaksi tulee levyoperaatiot ja nopeimpia toimintoja ovat sovelluksen sisäiset tapahtumat.

Bittioperaatioden käyttäminen tiedon tiivistämiseen vähentää siirretyn datan määrää ja toimii siinä hyvin.

Katso myös

Oheessa muutamia linkkejä, joiden takaa löytyy eri tavoin selitettynä miten bittioperaatiot toimivat. Toisissa käydään hyvin perusteellisesti asioita läpi ja toisissa painotetaan enemmän koodin toimintaa. Avaa muutama ja omaksu tiedot niistä, joista opit asian helpoimmin.

Post Navigation