[C#] Generics en inheritance

Pagina: 1
Acties:

  • bigben04
  • Registratie: December 2001
  • Laatst online: 16-02 17:30
Ik ben bezig met een groot project in Visual C# (framework 2.0) en zit nu met een probleem met generics. In versimpelde versie ziet het er als volgt uit:

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
public class Vehicle
{
}

public class Car : Vehicle
{
}


public class VehicleManager<T> where T : Vehicle
{
    List<T> vehicles;
}

public class CarManager : VehicleManager<Car>
{
}

public abstract class VehicleView
{
    public abstract void Initialize(VehicleManager<Vehicle> vehicleManager);
}

public class CarView : VehicleView
{
    private CarManager carManager;

    public override void Initialize(VehicleManager<Vehicle> vehicleManager)
    {
        // Cannot implicitly convert type
        // 'vehicles.VehicleManager<vehicles.Vehicle>'
        // to 'vehicles.CarManager'
        carManager = vehicleManager;

        // Cannot convert type 'vehicles.VehicleManager<vehicles.Vehicle>'
        // to 'vehicles.CarManager'
        carManager = (CarManager)vehicleManager;
    }
}


Het is dus in de CarView niet mogelijk om de parameter vehicle, van type VehicleManager<Vehicle> toe te wijzen aan of te casten naar de carManager van type CarManager, ondanks het feit dat een Car wel overerft van Vehicle.

Als de parameter verandert wordt naar een VehicleManager<Car> werkt het uiteraard wel, aangezien de CarManager direkt overerft van die klasse. Echter, dan kan ik de Initialize functie niet laten overerven en dat wil ik nu juist wel, zodat de Initialize op een variable van type VehicleView aangeroepen kan worden, wat dan op runtime een CarView is, of een TruckView, enzovoort.

Is er nu een mooie manier om dit op te lossen?

[ Voor 5% gewijzigd door bigben04 op 15-06-2006 12:36 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het is logisch dat het niet kan.
Stel je hebt een List<Vehicle>, en volgens jou verhaal zou je dat moeten kunnen casten naar een List<Object>. Echter, dat zou betekenen dat je er ook strings in mag stoppen, en dus zit je met String objecten in een List<Vehicle>. Dat mag natuurlijk niet :). (Volgens dezelfde redenatie mag je ook een Vehicle[] niet casten naar een Object[], ookal weet je zeker dat elke Vehicle minstens een Object is)

De oplossing is vrij simpel: die Initialize functie moet ook generiek zijn. Of misschien beter de VehicleView zelf, zodat CarView kan extenden van een VehicleView<Car>, maar waarschijnlijk is de functionaliteit van alle views hetzelfde zodat je die CarView niet eens nodig hebt

[ Voor 35% gewijzigd door .oisyn op 15-06-2006 12:55 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Kwistnix
  • Registratie: Juni 2001
  • Laatst online: 11:35
C#:
1
  <? extends Vehicle>


:?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mooie Java code in een C# code blokje :Y)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Kwistnix
  • Registratie: Juni 2001
  • Laatst online: 11:35
.oisyn schreef op donderdag 15 juni 2006 @ 12:50:
Mooie Java code in een C# code blokje :Y)
:D

Kan dus niet in c# ok, weer wat geleerd.
Ik dacht ik neem de gok :P

  • whoami
  • Registratie: December 2000
  • Laatst online: 19-02 23:53
Waarom maak je die class CarManager , als die eigenlijk niets van functionaliteit toevoegt ?

Eigenlijk is het de bedoeling dat je dan eigenlijk dit doet:

code:
1
VehicleManager<Car> carManager = new VehicleManager<Car>();


En verder, wat .oisyn zegt: je geeft een generieke parameter mee, en je wil die in een bepaalde , specifiekere variable steken. Dat kan je niet zomaar doen zonder te casten. En als je cast, moet je zeker zijn dat die generieke VehicleManager eigenlijk een CarManager is. Dus, dat zal je in je Initialize dan moeten testen.

[ Voor 42% gewijzigd door whoami op 15-06-2006 12:55 ]

https://fgheysels.github.io/


  • Mars Warrior
  • Registratie: Oktober 2003
  • Laatst online: 12:50

Mars Warrior

Earth, the final frontier

Jij wilt eigenlijk de voordelen van Generic lijsten (strong typing) combineren met de voordelen van de 'oude' manier van lijsten (casten naar elk willekeurig object).

Zou ik ook wel willen, maar dat gaat nu net met Generics niet. Deze zijn nu net in het leven geroepen om het moeten casten te vermijden...

Volgens mij moet je dus of:
1. afzien van generics en terugvallen op de 'oude' manier
2. toch generics gebruiken, maar dan het probleem van je CarManager op een totaal andere manier oplossen, al weet ik niet direct een echt generieke en elegante oplossing hiervoor ;(

Material 3 Thema's voor HA | Swiss Army Knife custom card voor HA | AmoebeLabs


  • bigben04
  • Registratie: December 2001
  • Laatst online: 16-02 17:30
Met dank aan de tip van .oisyn om de Initialize generiek te maken heb ik er het volgende van gemaakt:
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 Vehicle
{
}

public class Car : Vehicle
{
}

public class VehicleManager<T> where T : Vehicle
{
    List<T> vehicles;
}

public class CarManager : VehicleManager<Car>
{
}

public abstract class VehicleView<T, U> where T : VehicleManager<U>
    where U : Vehicle
{
    public abstract void Initialize(T vehicleManager);
}

public class CarView : VehicleView<CarManager, Car>
{
    private CarManager carManager;

    public override void Initialize(CarManager carManager)
    {
        this.carManager = carManager;
    }
}

Dit werkt inderdaad en op deze wijze hoeft er zelfs niet eens gecast te worden.
whoami schreef op donderdag 15 juni 2006 @ 12:54:
Waarom maak je die class CarManager , als die eigenlijk niets van functionaliteit toevoegt ?
Op zich heb je gelijk, maar dit is versimpelde voorbeeldcode, de specifieke managers voegen in de daadwerkelijke code wel functionaliteit toe.

Bedankt voor het meedenken in elk geval allemaal :)

edit: o ja FallenAngel666, niet naar het casino vandaag, het is niet jouw gokdag :+

[ Voor 7% gewijzigd door bigben04 op 15-06-2006 13:08 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Hou er wel rekening mee dat generics in veel gevallen je code er niet simpeler op maken. Dit soort regels code:
public abstract class VehicleView<T, U> where T : VehicleManager<U>
where U : Vehicle
vind ik bv al nauwelijks leesbaar, ookal snap ik wel wat er staat. Misschien dat je aan interfaces meer hebt, omdat die je code niet nodeloos ingewikkeld maken in sommige gevallen. Begrijp me niet verkeerd, generics zijn leuk, maar overdrijven kan verkeerd uitpakken. Just a FYI :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com

Pagina: 1