[C#] Subtypes bewaren in collectie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 00:53
De situatie is als volgt:

Ik heb een abstract class Ship. Hiervan bestaan een aantal subclasses; Carrier, Battleship, Submarine, Cruiser en Destroyer. Van deze subclasses worden een aantal instanties gemaakt die in een collectie worden gestopt. Vervolgens wil ik deze collectie uitlezen, op zo'n manier dat een Carrier gewoon een Carrier blijft, en een Battleship gewoon een Battleship.

Heel ingekort heb ik dus zoiets:
C#:
1
2
3
4
5
6
ArrayList Ships = new ArrayList();

foreach (Ship ship in Ships)
{
    // Doe iets met het type schip
}


Het schip in mijn foreach loop is op deze manier altijd van het type Schip. Dit is echter niet de bedoeling. Ik wil gewoon een Carrier, Battleship, etc.

Nu snap ik dat ik hem cast naar een Ship in de foreach loop, maar ik weet geen manier om dit niet te doen. Ook als ik er var of object van maak wordt het een Ship object. Dan heb je nog dynamic, maar daar kun je volgens mij niet zoveel mee.

Wie o wie helpt mij aan de (zeer waarschijnlijk zeer simpele) oplossing voor dit probleem?

Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

Waarom gebruik je geen strongly typed collection, sinds generics in .NET 2 worden weak typed collections voor de meeste use cases afgeraden.

Maargoed, zeg dat je een ICollection<Ship> hebt. Met LINQ kan je natuurlijk zoiets doen:
C#:
1
foreach (Carrier c in ships.OfType<Carrier>()) {}


Vergeet niet dat het voor C# een Ship is en geen Carrier in je collectie, maar voor de CLR is het gewoon een Carrier, Battleship etc.

Wat probeer je te bereiken?

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 00:53
Sebazzz schreef op maandag 02 mei 2011 @ 20:29:
Waarom gebruik je geen strongly typed collection, sinds generics in .NET 2 worden weak typed collections voor de meeste use cases afgeraden.
Dat deed ik ook. Ik was echter in de veronderstelling dat mijn probleem wellicht daardoor kwam.
Maargoed, zeg dat je een ICollection<Ship> hebt. Met LINQ kan je natuurlijk zoiets doen:
C#:
1
foreach (Carrier c in ships.OfType<Carrier>()) {}
Dan moet ik al van tevoren weten van welk type het schip is. Dat weet ik echter niet.
Wat probeer je te bereiken?
Verschillende schip-objecten opslaan in een collection, waarna ik met een enkele event handler kan kijken hoeveel schepen er al van een bepaald type zijn. Die event handler krijgt als parameter het type schip mee, waarna ik dit type wil vergelijken met de Type property van de schepen die in de collectie zitten.

Ik heb dus zoiets:

collection -> Carrier, Battleship, Submarine, Submarine

Elk schip heeft weer een property Type, die aangeeft wat voor type schip het is.

Vervolgens wil ik kijken: hoeveel objecten zitten er in mijn collectie waarvan dat type overeen komt. Dat lukt me alleen niet omdat alles van het type 'Ship' is.

Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 06-09 16:59

CoolGamer

What is it? Dragons?

Dan moet je "Type" definiëren in "Ship", waarna hem override in de subclassen. Dan kan je vanaf Ship ook bij die property.

[ Voor 22% gewijzigd door CoolGamer op 02-05-2011 20:42 ]

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 00:53
TheCoolGamer schreef op maandag 02 mei 2011 @ 20:42:
Dan moet je "Type" definiëren in "Ship", waarna hem override in de subclassen. Dan kan je vanaf Ship ook bij die property.
Dat doe ik nu al. Ik heb in Ship een public string Type, en in de subclasses ervan een public new string Type. Er wordt nu altijd het Type van Ship uitgelezen ipv het type van de subclasses.

Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 06-09 16:59

CoolGamer

What is it? Dragons?

Je moet niet new gebruiken, je moet override gebruiken. Hiervoor moet je de property in Ship wel virtual of abstract maken.

Voorbeeld: MSDN: How to: Define Abstract Properties (C# Programming Guide)

[ Voor 4% gewijzigd door CoolGamer op 02-05-2011 20:49 ]

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

Avalaxy schreef op maandag 02 mei 2011 @ 20:45:
[...]


Dat doe ik nu al. Ik heb in Ship een public string Type, en in de subclasses ervan een public new string Type. Er wordt nu altijd het Type van Ship uitgelezen ipv het type van de subclasses.
Dat is het probleem. Zoek eens naar het verschil van overriding versus redeclaration.

Je moet je property virtual of abstract maken.

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 00:53
Oeps, ik heb het verkeerd verwoord. Het is nu namelijk geen property maar een field. Vandaar de new vs override. Ik zal er eens een property van maken :)

Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

Protected of public fields worden afgeraden, dus dat is sowieso beter om er een property van te maken. ;)

[ Voor 4% gewijzigd door Sebazzz op 02-05-2011 20:53 ]

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 00:53
TheCoolGamer schreef op maandag 02 mei 2011 @ 20:48:
Je moet niet new gebruiken, je moet override gebruiken. Hiervoor moet je de property in Ship wel virtual of abstract maken.

Voorbeeld: MSDN: How to: Define Abstract Properties (C# Programming Guide)
Sebazzz schreef op maandag 02 mei 2011 @ 20:48:
[...]

Dat is het probleem. Zoek eens naar het verschil van overriding versus redeclaration.

Je moet je property virtual of abstract maken.
Dit heeft het probleem opgelost :D Allebei bedankt O+

Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 06-09 16:59

CoolGamer

What is it? Dragons?

Sebazzz schreef op maandag 02 mei 2011 @ 20:52:
Protected of private fields worden afgeraden, dus dat is sowieso beter om er een property van te maken. ;)
public bedoel je :>

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

Avalaxy schreef op maandag 02 mei 2011 @ 20:52:
[...]

Dit heeft het probleem opgelost :D Allebei bedankt O+
Wat is er trouwens mis met Object.GetType() en typeof(Class)?

Het is nog steeds niet duidelijk wat je met je Type property wil :+ :P

[ Voor 13% gewijzigd door Sebazzz op 02-05-2011 20:55 ]

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
nv dat werkt dus niet :(

[ Voor 126% gewijzigd door NC83 op 02-05-2011 21:04 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Wat is het idee achter de inheritance hierarchie? Als je via type onderscheid moet gaan maken, dan klopt er mogelijk iets niet. Een Ship definieert de methodes waar alle schepen zich mee moeten kunnen redden. Elk specifiek subtype kan deze methodes overriden. Je hoeft dan bij het doorlopen van zo'n verzameling niet te weten welk specifiek subtype je tegenkomt, je roept gewoon de methode aan.

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • kutagh
  • Registratie: Augustus 2009
  • Laatst online: 21:37
Sebazzz schreef op maandag 02 mei 2011 @ 20:54:
[...]

Wat is er trouwens mis met Object.GetType() en typeof(Class)?

Het is nog steeds niet duidelijk wat je met je Type property wil :+ :P
Zoals dit he?
code:
1
2
if(Ship.GetType() == typeof(Carrier))
   teller++;

Het lijkt mij beter om dit zo te doen, duidelijker leesbaar met hetzelfde effect...
code:
1
2
if(Ship is Carrier)
   teller++

(Zie ook: MSDN over 'is')

Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 00:53
Herko_ter_Horst schreef op maandag 02 mei 2011 @ 22:00:
Wat is het idee achter de inheritance hierarchie? Als je via type onderscheid moet gaan maken, dan klopt er mogelijk iets niet. Een Ship definieert de methodes waar alle schepen zich mee moeten kunnen redden. Elk specifiek subtype kan deze methodes overriden. Je hoeft dan bij het doorlopen van zo'n verzameling niet te weten welk specifiek subtype je tegenkomt, je roept gewoon de methode aan.
Yup, maar omdat ik een field gebruikte ipv een property werkte dat niet. Nu spreek ik via LINQ gewoon alles aan als een 'Ship' object en doet het er inderdaad niet toe van welk type deze is.

Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

kutagh schreef op maandag 02 mei 2011 @ 22:11:
[...]

Zoals dit he?
code:
1
2
if(Ship.GetType() == typeof(Carrier))
   teller++;

Het lijkt mij beter om dit zo te doen, duidelijker leesbaar met hetzelfde effect...
code:
1
2
if(Ship is Carrier)
   teller++

(Zie ook: MSDN over 'is')
Nee hij heeft het over een Type property. Dan is mijn oplossing beter. Overigens is 'is' niet gelijk aan GetType() == typeof() geloof ik (staat in CLR via C#).

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Nee ze zijn idd niet hetzelfde maar leiden in dit geval wel tot dezelfde oplossing. De "is" is ongeveer hetzelfde als een "dynamic_cast<T>" in C++ die enkel een geldige pointer returned als je de base naar een derived kan casten, enkel geeft de "is" een bool terug of het wel of niet een derived type van dat bepaalt soort is.

[ Voor 43% gewijzigd door NC83 op 03-05-2011 01:07 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Niet zo moeilijk om het aantal schepen v/e bepaald subtype op te vragen:

C#:
1
2
3
4
5
6
7
8
public int AmountOfType<T>(IEnumerable<Ship> ships) where T : Ship
{
  return ships.OfType<T>().Length();
}

/* ... */

int nrCarriers = this.AmountOfType<Carrier>(this.Ships);

Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 17-09 10:59

Ventieldopje

I'm not your pal, mate!

R4gnax schreef op dinsdag 03 mei 2011 @ 09:15:
Niet zo moeilijk om het aantal schepen v/e bepaald subtype op te vragen:

C#:
1
2
3
4
5
6
7
8
public int AmountOfType<T>(IEnumerable<Ship> ships) where T : Ship
{
  return ships.OfType<T>().Length();
}

/* ... */

int nrCarriers = this.AmountOfType<Carrier>(this.Ships);
Dan lijkt het me mooier als je dat in een public method zet van Ship.

C#:
1
int nrCarriers = this.Ships.AmountOfType<Carrier>();
NC83 schreef op dinsdag 03 mei 2011 @ 00:42:
Nee ze zijn idd niet hetzelfde maar leiden in dit geval wel tot dezelfde oplossing. De "is" is ongeveer hetzelfde als een "dynamic_cast<T>" in C++ die enkel een geldige pointer returned als je de base naar een derived kan casten, enkel geeft de "is" een bool terug of het wel of niet een derived type van dat bepaalt soort is.
Dat is dus het zelfde als GetType() == typeof() wat dus eigenlijk een bool expressie is. Je haalt het type op van een object en kijkt of dat overeenkomt met het type dat je nodig hebt. Je kunt dus prima is gebruiken, je hebt alleen GetType() nodig als je inderdaad het type wil weten ;)

[ Voor 40% gewijzigd door Ventieldopje op 03-05-2011 09:27 ]

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ventieldopje schreef op dinsdag 03 mei 2011 @ 09:21:
[...]
Dan lijkt het me mooier als je dat in een public method zet van Ship.

C#:
1
int nrCarriers = this.Ships.AmountOfType<Carrier>();
Ships is echter waarschijnlijk gewoon een normale collectie, en dan is he toevoegen van methodes nogal lastig, zonder dat je een subclass maakt
Dat is dus het zelfde als GetType() == typeof() wat dus eigenlijk een bool expressie is. Je haalt het type op van een object en kijkt of dat overeenkomt met het type dat je nodig hebt. Je kunt dus prima is gebruiken, je hebt alleen GetType() nodig als je inderdaad het type wil weten ;)
Wat NC83 ook al aangeeft, is dat het niet hetzelfde is aangezien de manier met GetType == typeof alleen werkt als het type exact gelijk is, en niet als het een subtype betreft.

“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!

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

H!GHGuY

Try and take over the world...

Herko_ter_Horst schreef op maandag 02 mei 2011 @ 22:00:
Wat is het idee achter de inheritance hierarchie? Als je via type onderscheid moet gaan maken, dan klopt er mogelijk iets niet. Een Ship definieert de methodes waar alle schepen zich mee moeten kunnen redden. Elk specifiek subtype kan deze methodes overriden. Je hoeft dan bij het doorlopen van zo'n verzameling niet te weten welk specifiek subtype je tegenkomt, je roept gewoon de methode aan.
Agreed. Ik zie nu al de volgende 10 lijnen code:
C#:
1
2
3
4
5
if (ship is Carrier)
  // Do carrier specific stuff
else if (ship is Destroyer)
  // Do destroyer specific stuff
else if ...

... en dan moet je je afvragen wat je van inheritance en andere OO-zaken begrepen hebt.

Mocht je effectief bovenstaande code willen gebruiken dan raad ik je aan om even double dispatch op te zoeken.

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 00:29
Woy schreef op dinsdag 03 mei 2011 @ 09:51:
[...]

Ships is echter waarschijnlijk gewoon een normale collectie, en dan is he toevoegen van methodes nogal lastig, zonder dat je een subclass maakt
Nee hoor, MSDN: Extension Methods (C# Programming Guide)

Zoiets dus: (geen idee of het werkt)
C#:
1
2
3
4
5
6
public static int AmountOfType<T>(this IEnumerable<Ship> ships) where T : Ship 
{ 
  return ships.OfType<T>().Length(); 
} 

int nrCarriers = this.Ships.AmountOfType<Carrier>(); 

[ Voor 24% gewijzigd door Caelorum op 03-05-2011 13:18 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Caelorum schreef op dinsdag 03 mei 2011 @ 13:15:
[...]

Nee hoor, MSDN: Extension Methods (C# Programming Guide)

Zoiets dus: (geen idee of het werkt)
C#:
1
2
3
4
5
6
public static int AmountOfType<T>(this IEnumerable<Ship> ships) where T : Ship 
{ 
  return ships.OfType<T>().Length(); 
} 

int nrCarriers = this.Ships.AmountOfType<Carrier>(); 
Ik weet best hoe extension methods werken. Er werd echter voorgesteld om het een public member function te maken, en dat kan natuurlijk niet zomaar. Als je een extension method maakt zou ik hem overigens gewoon op IEnumberable maken, het is immers iets wat je vaker op andere collecties zou kunnen gebruiken
C#:
1
2
3
4
5
6
public static int AmountOfType<T>(this IEnumerable enumerable)
{ 
  return enumerable.OfType<T>().Length(); 
} 

int nrCarriers = this.Ships.AmountOfType<Carrier>(); 

“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!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 00:29
Woy schreef op dinsdag 03 mei 2011 @ 13:48:
[...]Ik weet best hoe extension methods werken.
Het leek me al zo vreemd :)
Pagina: 1