[C#] Property van een Struct meegeven als argument in method

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Bitbored
  • Registratie: Oktober 2008
  • Laatst online: 08-07 15:05
Dag tweakers

Als laatste wanhoopsdaad vraag ik meestal nog eens om hulp op GoT, en dit heeft me in het verleden al wat oplossingen opgeleverd. Vandaar dat ik dit nu nogmaals probeer.

Ik ben bezig met wat oefenprogrammas te schrijven voor school in C#, en omdat ik me stierlijk verveel in die les maak ik het mezelf wat moeilijker >:)

De opdracht is het maken van een visualisatie van een koffiemachine, op een objectgeoriënteerde manier.
Nu is mijn eigen uitbreiding het gebruiken van static properties in structs om hoeveelheden verbruikte grondstoffen (water, koffie, bekertjes) aan te duiden.

Een beetje zoals gedaan wordt bij de constructor System.Drawing.SolidBrush(Color.Red) of System.Drawing.Pen(Color.Red) dus.
Hierbij is Color.Red een static property in de structure Color.

Mijn doel is het zelfde, ik wil een Methode maken in de class Koffiemachine met als argumenten 2 static properties. Ik laat de code voor zich spreken:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Labo5_Koffiemachine
{
    public partial class frmKoffiemachine : Form
    {
        public frmKoffiemachine()
        {
            InitializeComponent();
        }

        private void frmKoffiemachine_Load(object sender, EventArgs e)
        {
            Koffiemachine oKoffiemachine = new Koffiemachine();
            oKoffiemachine.MaakKoffie(Koffie.Klein, Suiker.Gewoon);
        }

    }
    public class Koffiemachine
    {
        //Grote bekers (10), kleine bekers (10), water (2 liter=200cl), koffie (100 gram) en suiker (50 gram).
        static int[] arriGrondstoffen = new int[5] {10, 10, 200, 100, 50};
        public Koffiemachine()
        {
        }
        public int AantalGroteBekers
        {
            set
            {
                arriGrondstoffen[0] = Convert.ToInt32(value);
            }
            get
            {
                return arriGrondstoffen[0];
            }
        }
        public int AantalKleineBekers
        {
            set
            {
                arriGrondstoffen[1] = Convert.ToInt32(value);
            }
            get
            {
                return arriGrondstoffen[1];
            }
        }

        
        public void MaakKoffie(Koffie arriKoffie, Suiker iSuiker)
        {
            //maak koffie
        }
    }
}

/// <summary>
/// Struct Koffie, geeft een array terug als (iGrotebekers, iKleinebekers, iWaterCl, iKoffieGram, iTijd)
/// </summary>
public struct Koffie
{
    //Grote koffie verbruikt 1 grote beker, 25cl water en 15 gram koffie. 
    //De kleine variant verbruikt 1 kleine beker, 20cl water en 10 gram koffie.
    //Tijden: Groot (7 sec), Klein (4 sec) en toevoeging van suiker (1 sec).
    private static int[] arriGroot = {1, 0, 25, 15, 7};
    private static int[] arriKlein = {0, 1, 20, 10, 4};
    public static int[] Groot
    {
        get;
    }
    public static int[] Klein
    {
        get
        {
            return arriKlein;
        }
    }
}

/// <summary>
/// Struct Suiker, geeft een array terug als iSuiker in Gram
/// </summary>
public struct Suiker
{
    //Suiker gewoon (3 gram) en suiker
    //extra (6 gram).
    private static int arriGewoon = 3;
    private static int arriExtra = 6;
    public static int Gewoon
    {
        get
        {
            return arriGewoon;
        }
    }
    public static int Extra
    {
        get
        {
            return arriExtra;
        }
    }
}


Dit geeft me natuurlijk als error dat de int[] Koffie.Klein niet van het type Koffie is en dat int Suiker.Gewoon niet van het type Suiker is. Ik zie dus duidelijk ergens iets over het hoofd, en na een aantal uren opzoekingswerk op internet en het irriteren van enkele medestudenten en docenten heb ik de oplossing nog niet gevonden.

Kan iemand op GoT me helpen?

Acties:
  • 0 Henk 'm!

  • mlo
  • Registratie: Juli 2010
  • Laatst online: 17-09 06:56

mlo

iets met een klok en een klepel?
Hint: enum

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
idd, een enum is waarschijnlijk wat je zoekt.

Als alternatief: instanties. new Suiker(3) en je hebt een Suiker-object met 3 gram suiker (mits je een class Suiker aanmaakt, natuurlijk). Een const 'arriGewoon = new Suiker(3)' en je hebt het ook.

'Constante' objecten worden ook weer vaak als enums weergegeven ipv constante objecten, dan kun je er nog zooi omheen doen (om het maar even a-technisch uit te leggen, het is half 11 x))

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Of als je het toch wilt doen met voorgeconfigureerde instances (zoals bijvoorbeeld Color of CultureInfo in het .NET framework doen):

C#:
1
2
3
4
5
6
7
8
9
10
11
public struct Sugar
{
  public static readonly Sugar Normal = new Sugar(3);
  public static readonly Sugar Extra = new Sugar(6);

  public Sugar(int grams) {
    Grams = grams;
  }

  public int Grams { get; private set; }
}


Oh; en houdt alsjeblieft op met die lamme Hungarian notatie. Bij weakly typed talen zoals PHP is er nog een argument voor te maken, maar bij strongly typed talen zoals C# is het echt not done.

[ Voor 20% gewijzigd door R4gnax op 25-10-2011 08:59 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verder lijkt het me niet handig om dit met statics op te lossen. Als je straks een tweede Koffiemachine wil hebben dan werkt dat niet meer. Je kunt het beter gewoon als eigenschap van de Koffiemachine zelf opslaan.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Je zou het ook op deze manier kunnen doen?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Suiker
{
    public int Hoeveelheid { get; private set; }

    public Suiker(Hoeveelheid hoeveelheid) : this()
    {
        Hoeveelheid = (int)hoeveelheid;
    }
}

public enum Hoeveelheid
{
    Gewoon = 3,
    Extra = 6
}


En dan binnen het programma aanroepen als:

C#:
1
2
Suiker suiker = new Suiker(Hoeveelheid.Gewoon);
string output = string.Format("Hoeveelheid suiker: {0}", suiker.Hoeveelheid);

Acties:
  • 0 Henk 'm!

  • stp_4
  • Registratie: Maart 2003
  • Laatst online: 20:25
Verwijderd schreef op dinsdag 25 oktober 2011 @ 09:04:
Je zou het ook op deze manier kunnen doen?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Suiker
{
    public int Hoeveelheid { get; private set; }

    public Suiker(Hoeveelheid hoeveelheid) : this()
    {
        Hoeveelheid = (int)hoeveelheid;
    }
}

public enum Hoeveelheid
{
    Gewoon = 3,
    Extra = 6
}


En dan binnen het programma aanroepen als:

C#:
1
2
Suiker suiker = new Suiker(Hoeveelheid.Gewoon);
string output = string.Format("Hoeveelheid suiker: {0}", suiker.Hoeveelheid);
Kun je van die public property Hoeveelheid niet beter ook gewoon die enum gebruiken?

stp - PSN ID: stp_4


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik zie hier overigens ook de mogelijkheid om gebruik te maken van het Builder Pattern. Aangezien het voor school is kun je daar vast nog wel punten mee scoren ;)

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

stp_4 schreef op dinsdag 25 oktober 2011 @ 09:10:
[...]


Kun je van die public property Hoeveelheid niet beter ook gewoon die enum gebruiken?
Zou je kunnen doen maar dan zou je het toch nog uiteindelijk naar een int moeten casten om de waarde er uit te halen, nu wordt deze als retour waarde aangeboden.

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

stp_4 schreef op dinsdag 25 oktober 2011 @ 09:10:
Kun je van die public property Hoeveelheid niet beter ook gewoon die enum gebruiken?
Eigenlijk niet, omdat door de enum input je een beperkte lijst van invoer hebt, maar de rest van het systeem gewoon een aantal wilt. Ik zou alleen de naam van de public property anders noemen om verwarring tussen enum en int te voorkomen.

Ik in gevallen zoals deze ben ik eigenlijk tegen het gebruik van enums omdat je later zonder rebuild de waardes niet meer kunt aanpassen. De enum heeft bijvoorbeeld niet de optie 'geen'. Er zijn ook mensen welke geen suiker in de koffie willen.

Een enum moet eigenlijk alleen gebruikt worden als de definitie alleen in de code bestaat. Denk daarbij vooral aan state enumerations. Normaal zou ik een ISuikerRepository gebruiken welke uit een XML of CSV bestand de definities haalt en deze als een ICollection<Suiker> beschikbaar maakt. Dat gaat misschien voor een school opdracht te ver, maar ik verwacht een dergelijke opzet wel van mijn developers.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

Verwijderd

Eigenlijk niet, omdat door de enum input je een beperkte lijst van invoer hebt, maar de rest van het systeem gewoon een aantal wilt. Ik zou alleen de naam van de public property anders noemen om verwarring tussen enum en int te voorkomen.
Daarin heb je volledig gelijk, dit kan verwarrend over komen.
Ik in gevallen zoals deze ben ik eigenlijk tegen het gebruik van enums omdat je later zonder rebuild de waardes niet meer kunt aanpassen. De enum heeft bijvoorbeeld niet de optie 'geen'. Er zijn ook mensen welke geen suiker in de koffie willen.
Ik wist wel dat ik iemand vergeten was! :9

Ik ben zelf nog niet zo heel erg ver gevorderd in dit, maar waarom een interface aanbieden die zijn waardes uit een XML of CSV haalt?
Is daar een specifieke reden voor, en is daar enige documentatie in boek of online vorm die het eventueel uitlegt?

Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Verwijderd schreef op dinsdag 25 oktober 2011 @ 09:04:
Je zou het ook op deze manier kunnen doen?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Suiker
{
    public int Hoeveelheid { get; private set; }

    public Suiker(Hoeveelheid hoeveelheid) : this()
    {
        Hoeveelheid = (int)hoeveelheid;
    }
}

public enum Hoeveelheid
{
    Gewoon = 3,
    Extra = 6
}


En dan binnen het programma aanroepen als:

C#:
1
2
Suiker suiker = new Suiker(Hoeveelheid.Gewoon);
string output = string.Format("Hoeveelheid suiker: {0}", suiker.Hoeveelheid);
Het is echt gruwelijk slecht om de onderliggende waardes van een enumeratie semantiek te geven. Soms is dat te rechtvaardigen, hier -zeker- niet. Wat als "extra" straks 4 of erger, 4.5 gram suiker moet worden?

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

Verwijderd

Grappig is het altijd dat mensen kritiek geven maar geen eventuele (betere) voorbeelden?
Wat stel je dan zelf voor?

Misschien?
C#:
1
2
3
4
5
6
7
8
struct Suiker
{
    public float Hoeveelheid { get; private set; }
    public Suiker(float hoeveelheid)
    {
        Hoeveelheid = hoeveelheid;
    }
}

Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Ik zie niet in waarom ik je alles voor zou moeten kauwen. Neem mijn opmerking ter harte, en denk zelf maar na hoe het dan beter zou moeten kunnen.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

Verwijderd

Kijk dat vind ik nu echt een beetje een rare houding, je bent wel zo aardig om te commenteren maar als er wordt gevraagd van: Goh, hou zou jij het doen dan?
Dan wordt dat meteen beantwoord met: Ik ga je niet alles zitten voorkauwen zoek het zelf maar uit.
Nou waarom reageer je er dan op?
Ik zie het nut er niet van in, buiten dat je even lekker de slimmerik kan uithangen.

De TS vroeg toch om advies?
Dat mijn advies zeker niet het beste is, dat is bewezen.
Maar zo'n antwoord als je dan hier tegemoet komt slaat ook nergens op, waar is een forum als dit anders voor dan?

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Bitbored schreef op maandag 24 oktober 2011 @ 22:09:
Een beetje zoals gedaan wordt bij de constructor System.Drawing.SolidBrush(Color.Red) of System.Drawing.Pen(Color.Red) dus.
Hierbij is Color.Red een static property in de structure Color.
Even om deze verwarring uit de wereld te helpen. De term voor deze zaken is constants. Een constante is iets wat je niet kunt veranderen. Een "static property" is een wat lastiger term want "static" en "property" zijn in C# iets anders en bovendien iets wat je zo min mogelijk gebruikt (in combinatie).
Verwijderd schreef op dinsdag 25 oktober 2011 @ 13:55:
Kijk dat vind ik nu echt een beetje een rare houding, je bent wel zo aardig om te commenteren maar als er wordt gevraagd van: Goh, hou zou jij het doen dan?
Dan wordt dat meteen beantwoord met: Ik ga je niet alles zitten voorkauwen zoek het zelf maar uit.
Nou waarom reageer je er dan op?
Ik zie het nut er niet van in, buiten dat je even lekker de slimmerik kan uithangen.

De TS vroeg toch om advies?
Dat mijn advies zeker niet het beste is, dat is bewezen.
Maar zo'n antwoord als je dan hier tegemoet komt slaat ook nergens op, waar is een forum als dit anders voor dan?
Je oplossing is raar en hij geeft precies aan wat er mis mee is.

[ Voor 38% gewijzigd door Hydra op 25-10-2011 15:30 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Hydra schreef op dinsdag 25 oktober 2011 @ 15:29:
[...]


Even om deze verwarring uit de wereld te helpen. De term voor deze zaken is constants. Een constante is iets wat je niet kunt veranderen. Een "static property" is een wat lastiger term want "static" en "property" zijn in C# iets anders en bovendien iets wat je zo min mogelijk gebruikt (in combinatie).
Correct me if I'm wrong, maar is het niet juist andersom, in ieder geval in C# dan (waar deze thread toch om gaat)?
De Color.Red, Brushes.Blue, etc, zijn voor zover ik weet inderdaad static (read-only) properties, dat wil zeggen properties zonder setter. Sterker nog, C# zelf vind deze waardes juist niet constants, je kan ze namelijk (bijvoorbeeld) niet als default waarde van een optional parameter gebruiken:
C#:
1
void Test(Color c = Color.Red) {}

"Default parameter value for 'c' must be a compile-time constant"

Dat ze uiteindelijk wel constant (in de 'spreektaal' zin van het woord) zijn is natuurlijk waar, maar dat is alleen maar omdat de waarden die door de property getters worden terug gegeven nooit veranderd worden. De Color structure zou in principe best een methode kunnen hebben die de waarde Color.Red veranderd (tenzij die een readonly field terug geeft, wat vast wel zo is, maar verder niet echt relevant is).

Voor zover ik begrijp zijn constants waarden die nooit veranderd kunnen worden, terwijl deze static (readonly) properties niet veranderd zullen worden.

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • Capital_G
  • Registratie: Oktober 2006
  • Laatst online: 29-08 10:34
NickThissen schreef op dinsdag 25 oktober 2011 @ 16:17:
[...]

Correct me if I'm wrong, maar is het niet juist andersom, in ieder geval in C# dan (waar deze thread toch om gaat)?
Static properties zijn een redelijke niche. Een property geeft over het algemeen toegang tot een veld van een class, en is per definitie dus niet statisch, dat is gewoon niet logisch.

Het pattern wat jij beschrijft is een uitzondering hierop, door readonly static fields te declareren is het mogelijk om een class te maken die een enum imiteert. Het is een redelijke oplossing voor de tekortkomingen van de C# enum, het geeft je wat meer mogelijkheden.

Dat is allemaal echter niet erg relevant, ik zag de Builder pattern langskomen hierboven, dat is een betere optie. Dat geeft je wat meer mogelijkheden.

C#:
1
2
Suiker suiker = Suiker.FromGrains(5);
Suiker meerSuiker = Suiker.FromHoeveelheid(Hoeveelheid.Bergen);

Acties:
  • 0 Henk 'm!

  • alwinuzz
  • Registratie: April 2008
  • Laatst online: 20:30
Je kan ook static properties hebben. Voorbeeld van de TS, Color.Red, is een static readonly (alleen get) property.
Een static readonly field kan ook.

Bitbored, om te beginnen snap ik niet waarom je struct gebruikt, het heeft bijna nooit meerwaarde (IMO :) ). Misschien omdat Color ook een struct is?
En ik snap niet zo goed waarom je voor elke grondstof (koffiepoeder, suiker etc) een eigen class wil?

Een class voor de koffiemachine (met een prop voor elke beschikbare grondstof), en een class voor een kopje koffie (met een prop voor lek benodigde grondstof) lijkt me genoeg.
De eenheid van je 'data' is een kopje koffie. En dan is er een machine die daar iets mee doet.

Voorbeeldje:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// geschreven in notepad, compileert vast niet

public enum Bekertje {Groot, Klein}

public class KopjeKoffie
{
    public decimal GramKoffie (get; set;)
    public decimal LiterWater (get; set;)
    public Bekertje Bekertje (get; set;)

    public decimal GramSuiker (get; set;)
    // Builder pattern
    public KopjeKoffie MetSuikerGewoon()
    {
        GramSuiker = 3;
        return this;
    }

    
    // dit zijn een soort presets
    // had ook een static readonly property kunnen zijn, net als Color.Red
    // maar met een functie duidelijker dat het iets doet (nieuw KopjeKoffie maken)
    public static KopjeKoffie MaakGroteKoffie()
    {
        // dit is een object initializer, geen ctor nodig
        return new KopjeKoffie {GramKoffie = 10, LiterWater = 0.20, Bekertje = Bekertje.Groot};
    }
}

public class KoffieMachine
{
    public void MaakKoffie(KopjeKoffie koffie)
    {
        // pruttel pruttel
    }
}

// in je form
private void frmKoffiemachine_Load(object sender, EventArgs e) 
{ 
    var machine = new Koffiemachine(); 
    var koffieKeuze = KopjeKoffie.MaakGroteKoffie().MetSuikerGewoon();
    oKoffiemachine.MaakKoffie(Koffie.Klein); 
} 

Acties:
  • 0 Henk 'm!

  • Bitbored
  • Registratie: Oktober 2008
  • Laatst online: 08-07 15:05
Enums zijn wel degelijk wat ik nodig heb.

Ik heb te veel gefixeerd gezocht naar de werking van static properties en methods door te veel op mijn voorbeeld van de Color struct te rekenen.

@R4gnax: I agree, maar dat zijn nu eenmaal de regels van onze leerkracht :F . Ik heb hier al tegen proberen te rebelleren door elke variable met een prefix o (van Object) te benoemen, maar achteraf gezien kies ik toch voor punten in plaats van overtuiging. :X
Niemand_Anders schreef op dinsdag 25 oktober 2011 @ 09:25:
[...]
Een enum moet eigenlijk alleen gebruikt worden als de definitie alleen in de code bestaat. Denk daarbij vooral aan state enumerations. Normaal zou ik een ISuikerRepository gebruiken welke uit een XML of CSV bestand de definities haalt en deze als een ICollection<Suiker> beschikbaar maakt. Dat gaat misschien voor een school opdracht te ver, maar ik verwacht een dergelijke opzet wel van mijn developers.
Het is wel degelijk de bedoeling dat enkel de vooraf bepaalde waarden bruikbaar zijn, ook al zou ik dit in de praktijk (lees: een echt, niet zuiver educatief programma) ook nooit zo doen.

Verder heb ik me ook al beziggehouden met het uitlezen van een XML bestand om een panel te vullen met wat pictureboxes en labels, terwijl het de bedoeling was dat dit gewoon via de designer werd gedaan.
Een beetje overkill kan nooit kwaad :).
Het is ondertussen al de 3de keer dat ik les krijg over object georiënteerd programmeren in .NET, en ik moet me toch ergens mee bezig houden terwijl de rest bezig fotootjes aan het verslepen is :)
Want jawel, we beginnen dit jaar weer vanaf het begin -.-
Ik ben vrij zeker dat ik ergens in die 4 jaar al eens enums ben tegengekomen (ik herinner me vaag een of ander kaartspel in vb.net), en dat is bij deze dan weer eens opgefrist.

Bedankt!

Acties:
  • 0 Henk 'm!

Verwijderd

Bitbored schreef op dinsdag 25 oktober 2011 @ 23:22:
Enums zijn wel degelijk wat ik nodig heb.

Ik heb te veel gefixeerd gezocht naar de werking van static properties en methods door te veel op mijn voorbeeld van de Color struct te rekenen.

@R4gnax: I agree, maar dat zijn nu eenmaal de regels van onze leerkracht :F . Ik heb hier al tegen proberen te rebelleren door elke variable met een prefix o (van Object) te benoemen, maar achteraf gezien kies ik toch voor punten in plaats van overtuiging. :X


[...]


Het is wel degelijk de bedoeling dat enkel de vooraf bepaalde waarden bruikbaar zijn, ook al zou ik dit in de praktijk (lees: een echt, niet zuiver educatief programma) ook nooit zo doen.

Verder heb ik me ook al beziggehouden met het uitlezen van een XML bestand om een panel te vullen met wat pictureboxes en labels, terwijl het de bedoeling was dat dit gewoon via de designer werd gedaan.
Een beetje overkill kan nooit kwaad :).
Het is ondertussen al de 3de keer dat ik les krijg over object georiënteerd programmeren in .NET, en ik moet me toch ergens mee bezig houden terwijl de rest bezig fotootjes aan het verslepen is :)
Want jawel, we beginnen dit jaar weer vanaf het begin -.-
Ik ben vrij zeker dat ik ergens in die 4 jaar al eens enums ben tegengekomen (ik herinner me vaag een of ander kaartspel in vb.net), en dat is bij deze dan weer eens opgefrist.

Bedankt!
Let wel op het disposen van je objecten bij het lezen van XML-bestanden. Dat zou je toch bonuspunten moeten opleveren ;). Want dat leert men je meestal niet...

Acties:
  • 0 Henk 'm!

Verwijderd

alwinuzz schreef op dinsdag 25 oktober 2011 @ 19:24:
...
En ik snap niet zo goed waarom je voor elke grondstof (koffiepoeder, suiker etc) een eigen class wil?

Een class voor de koffiemachine (met een prop voor elke beschikbare grondstof), en een class voor een kopje koffie (met een prop voor lek benodigde grondstof) lijkt me genoeg.
De eenheid van je 'data' is een kopje koffie. En dan is er een machine die daar iets mee doet.
...
Wat als de koffiemachine ook thee aan moet bieden (wat bij grote apparaten zo is). Of capuccino met extra melk. Of als je meerdere soorten suiker wil (bijv. aspartaam). Of... of...

Hangt van de business case af; als oefenopdracht lijkt het me juist wel verstandig het wat generieker op te zetten; geeft ook meer voldoening.

Het enige waar je -zonder achtergrondinformatie- 100% zeker van kan zijn is dat er iets van een beker moet zijn; maar die kan ook nog uit een een beker dispenser komen of er zelf worden ondergezet en verschillende formaten hebben. Ik zou die waarschijnlijk modelleren als de kern van het bestelproces en daaromheen alles structureren (dus ik verwacht een Beker klasse met bijv. een kleine en grote subklasse of configureerbare omvang). Het verbruik van de hoeveelheid water/koffie zou je in een omrekenformule kunnen doen i.p.v. harde waarden zoals nu. In Italië kwam ik een apparaat tegen die 4 formaten aanbood!

[ Voor 36% gewijzigd door Verwijderd op 27-10-2011 14:01 ]


Acties:
  • 0 Henk 'm!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 00:29
Verwijderd schreef op donderdag 27 oktober 2011 @ 13:49:
[...]
Het enige waar je -zonder achtergrondinformatie- 100% zeker van kan zijn is dat er iets van een beker moet zijn;
1 woord: koffiekan ;)

Acties:
  • 0 Henk 'm!

Verwijderd

8)7 haha
ik wil het beestje wel "container" gaan noemen maar dan wordt de code wel heel erg :?

Goed moment om weer eens YAGNI toe roepen.

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Verwijderd schreef op dinsdag 25 oktober 2011 @ 09:35:
Ik ben zelf nog niet zo heel erg ver gevorderd in dit, maar waarom een interface aanbieden die zijn waardes uit een XML of CSV haalt?
Is daar een specifieke reden voor, en is daar enige documentatie in boek of online vorm die het eventueel uitlegt?
Ik had al aangegeven dat het voor een huiswerk opdracht wat ver gaat, maar wij houden bij development de SOLID methode aan. De S staat voor Single Responsibility Principle, maar ook vaak als Seperation of Concerns aangeduid. Dit houd in dat een class voor slechts 1 taak mag zorgen. Het laden van een lijst met voorkeuren (geen, weinig, normaal, extra suiker) en deze als een instantie van Suiker terug geven wordt dan ook gezien als een aparte taak.

De interface komt eigenlijk terug in de I van solid, namelijk interface segregation. Jouw programma wil alleen een verzameling van Suiker instanties hebben. Waar deze vandaan komen is niet belangrijk. Het programma gebruikt dus alleen ISuikerRepository en de IoC container geeft dan bijvoorbeeld een CsvSuikerRepository of een XmlSuikerRepository terug.

Uncle Bob heeft een goede beschrijving van SOLID en verwacht technieken op zijn website staan.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class CsvSuikerRepository : ISuikerRepository
{
   private readonly List<Suiker> suikers;

   public CsvSuikerRepository(IConfig config)
   {
     //create and setup parser instance
     FileHelpersParser<SugarRecord> parser = new FileHelpersParser<SugarRecord>();
     parser.Encoding = Encoding.UTF8;

     //validate CSV location
     string csvLocation = config.Get("SugerCsvLocation", string.Empty);
     if (string.IsNullOrEmpty(csvLocation))
        throw new ApplicationException("Suger CSV location not defined");

     var sugars = parser.ReadFile(csvLocation);
     foreach(var sugar in sugars)
        suikers.Add(new Suiker(sugar.Description. sugar.Weight));
   }

   public ICollection<Suiker> Suikers { get { return suikers; } }


  //ternal struct for reading CSV records
  [DelimitedRecord(",")]
  private class SugerRecord
  {
    [FieldQuoted('"')]
    public string Description;
    public int Weight;
  }
}

De FileHelpers library is een echte aanrader als je met CSV bestanden aan de slag moet. Bovenstaande class heeft slechts 1 taak en dat is het inlezen van een CSV bestanden en vervolgens een verzameling Suiker instanties terug geven. IConfig is een class welke wij intern gebruiker en welke de configuratie uit de database haalt.

Het voor is een class als deze niet lastig om unit tests te schrijven. Als je deze class als een singleton voor je IoC container defineerd, dan is het wel verstandig om ook een file watcher toe te voegen welke de verzameling opnieuw inleest als de CSV wordt gewijzigd.

disclaimer: bovenstaande code heb ik even snel uit m'n hoofd geschreven.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

Verwijderd

Niemand_Anders schreef op vrijdag 28 oktober 2011 @ 16:13:
[...]

Ik had al aangegeven dat het voor een huiswerk opdracht wat ver gaat, maar wij houden bij development de SOLID methode aan. De S staat voor Single Responsibility Principle, maar ook vaak als Seperation of Concerns aangeduid. Dit houd in dat een class voor slechts 1 taak mag zorgen. Het laden van een lijst met voorkeuren (geen, weinig, normaal, extra suiker) en deze als een instantie van Suiker terug geven wordt dan ook gezien als een aparte taak.

De interface komt eigenlijk terug in de I van solid, namelijk interface segregation. Jouw programma wil alleen een verzameling van Suiker instanties hebben. Waar deze vandaan komen is niet belangrijk. Het programma gebruikt dus alleen ISuikerRepository en de IoC container geeft dan bijvoorbeeld een CsvSuikerRepository of een XmlSuikerRepository terug.

Uncle Bob heeft een goede beschrijving van SOLID en verwacht technieken op zijn website staan.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class CsvSuikerRepository : ISuikerRepository
{
   private readonly List<Suiker> suikers;

   public CsvSuikerRepository(IConfig config)
   {
     //create and setup parser instance
     FileHelpersParser<SugarRecord> parser = new FileHelpersParser<SugarRecord>();
     parser.Encoding = Encoding.UTF8;

     //validate CSV location
     string csvLocation = config.Get("SugerCsvLocation", string.Empty);
     if (string.IsNullOrEmpty(csvLocation))
        throw new ApplicationException("Suger CSV location not defined");

     var sugars = parser.ReadFile(csvLocation);
     foreach(var sugar in sugars)
        suikers.Add(new Suiker(sugar.Description. sugar.Weight));
   }

   public ICollection<Suiker> Suikers { get { return suikers; } }


  //ternal struct for reading CSV records
  [DelimitedRecord(",")]
  private class SugerRecord
  {
    [FieldQuoted('"')]
    public string Description;
    public int Weight;
  }
}

De FileHelpers library is een echte aanrader als je met CSV bestanden aan de slag moet. Bovenstaande class heeft slechts 1 taak en dat is het inlezen van een CSV bestanden en vervolgens een verzameling Suiker instanties terug geven. IConfig is een class welke wij intern gebruiker en welke de configuratie uit de database haalt.

Het voor is een class als deze niet lastig om unit tests te schrijven. Als je deze class als een singleton voor je IoC container defineerd, dan is het wel verstandig om ook een file watcher toe te voegen welke de verzameling opnieuw inleest als de CSV wordt gewijzigd.

disclaimer: bovenstaande code heb ik even snel uit m'n hoofd geschreven.
SOLID en Seperation of Concerns zijn twee verschillende dingen.. Seperation of Concerns is wel een onderdeel van SOLID. Overigens zit in jouw voorbeeld een behoorlijk aantal bad practises, je code is dunglish (Combinatie van NL en engels) en geneste classes :P Overigens kun je deze class ook niet correct unittesten. Je FileHelper zit er namelijk nog in, die zou je ook eruit moeten halen en interfacen.

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

R4gnax schreef op dinsdag 25 oktober 2011 @ 08:56:
Oh; en houdt alsjeblieft op met die lamme Hungarian notatie. Bij weakly typed talen zoals PHP is er nog een argument voor te maken, maar bij strongly typed talen zoals C# is het echt not done.
Het is _geen_ Hungarian notation:
http://www.joelonsoftware.com/articles/Wrong.html

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 00:29
Er bestaan twee soorten Hungarian notation: system en app. In dit geval zou ik zeggen dat het een slap aftreksel is van system hungarian.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Het is zoals genoemd dus inderdaad een slappe versie van systems hungarian.

Daarnaast wordt er in het aangehaalde artikel finaal mis geschoten. De correcte manier om het safe/unsafe string gebeuren af te handelen in een strongly-typed taal is een specifeke ISafeString interface te gebruiken i.c.m. een factory. Daarmee dwing je tijdens compile-time al af dat alle invoer waar vereist een veilige string is. (En nee; je moet het niet andersom doen. Het moet zo zijn dat het veilig maken van een string een bewuste actie is.)

Zie bijvoorbeeld: http://geekswithblogs.net...ng-and-mvchtmlstring.aspx

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Verwijderd schreef op vrijdag 28 oktober 2011 @ 18:30:
[...]
SOLID en Seperation of Concerns zijn twee verschillende dingen.. Seperation of Concerns is wel een onderdeel van SOLID. Overigens zit in jouw voorbeeld een behoorlijk aantal bad practises, je code is dunglish (Combinatie van NL en engels) en geneste classes :P Overigens kun je deze class ook niet correct unittesten. Je FileHelper zit er namelijk nog in, die zou je ook eruit moeten halen en interfacen.
Single Responsibility Pattern en Seperation of Concerns liggen heel erg dicht bij elkaar. De reden dat ik hier half Nederlands/Engels heb gebruik is omdat 'Suiker' al eerder in dit topic is genoemd. Wij gebruiken normaal alleen de Engelse taal, tenzij een term specifiek Nederlands is (denk aan Clieop03 (bestands formaat) en Bsn).

Wij hebben zelf wel een ICsvParser<T> interface, maar als ik in dit voorbeeld alles uit elkaar trek en het voorbeeld dan geen 32 regels is, maar al snel tegen de 100 regels zal lopen, dan is de focus weg. Namelijk waarom ik adviseer gebruik te maken van een ISuikerRepository.

En als je dan toch aan het afgeven bent op de code, ben je de belangrijkste fout vergeten. 'suikers' (regel 3) wordt nooit geinitialiseerd, dus regel 18 zal een NullReferenceException geven.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

Verwijderd

Dank je wel dat je het even wilde toelichten, ik zal het eens even goed doorlezen! :D

Acties:
  • 0 Henk 'm!

  • supreme tweaker
  • Registratie: December 2002
  • Laatst online: 28-08 01:27
Ik wil graag even aantekenen dat ik toch een beetje moest lachen om al deze .net koningen die bij het simpelweg modelleren van een klontje suiker, allerlei uitbereidbare, dynamische, "SOLID", zelfs file based (XML/CSV werdt al genoemd) uitvluchten bedenken, zonder dat de TS hier nu echt mee geholpen worden. En dan wordt er ook nog geruzied over al dan niet hungarian notation

OT: Je probleem is simpel; je wil een kopje koffie een suiker-waarde geven, en voor de leukigheid zou het fijn zijn als je er leesbare presets zijn. De oplossing die eerder werd genoemd door Mostrow is zo gek nog niet, maar alleen voor deze situatie. Dit is dan ook de directe oplossing voor dit probleem.

Mocht je later nog de exacte waarde van de definitie "Extra" willen aanpassen (op runtime), dan zul je toch logischerwijs een andere structuur moeten kiezen. Het builder pattern zou wel mooi zijn hiervoor, dan kan je dit naar hartelust dynmaisch oplossen, desnoods met zo'n prachtige ISuikerRepository.

Als ik de TS was zou ik me er voorlopig nog niet druk om maken.

Burp


Acties:
  • 0 Henk 'm!

  • alwinuzz
  • Registratie: April 2008
  • Laatst online: 20:30
Ja maar TS wil graag bonuspunten scoren door de boel te over-engineren :P

Acties:
  • 0 Henk 'm!

Verwijderd

Niemand_Anders schreef op zaterdag 29 oktober 2011 @ 16:10:
[...]

Single Responsibility Pattern en Seperation of Concerns liggen heel erg dicht bij elkaar. De reden dat ik hier half Nederlands/Engels heb gebruik is omdat 'Suiker' al eerder in dit topic is genoemd. Wij gebruiken normaal alleen de Engelse taal, tenzij een term specifiek Nederlands is (denk aan Clieop03 (bestands formaat) en Bsn).

Wij hebben zelf wel een ICsvParser<T> interface, maar als ik in dit voorbeeld alles uit elkaar trek en het voorbeeld dan geen 32 regels is, maar al snel tegen de 100 regels zal lopen, dan is de focus weg. Namelijk waarom ik adviseer gebruik te maken van een ISuikerRepository.

En als je dan toch aan het afgeven bent op de code, ben je de belangrijkste fout vergeten. 'suikers' (regel 3) wordt nooit geinitialiseerd, dus regel 18 zal een NullReferenceException geven.
Heb je allemaal gelijk in (laatste had ik idd ook gemist), maar als jij wilt laten zien hoe het netjes moet, dan moet je natuurlijk zelf geen bad practises/fouten erin zetten. Dat werkt namelijk dan tegengesteld.... Dat is voornamelijk mijn punt. En dichtbij elkaar is natuurlijk niet hetzelfde als dat het hetzelfde is.

Maar ik geloof dat de TS er zo genoeg van opsteekt nu :)
Pagina: 1