[.Net] Generics - niet kunnen casten naar base-type

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik loop steeds tegen het volgende generics probleem aan. Zie onderstaande code:

code:
1
2
3
4
public interface IMyInterface
{
    ICollection<object> Items { get; }
}


en

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyImpementation<T> : IMyInterface
    where T : object
{
    ICollection<T> _items;

    public ICollection<object> Items 
    {
        get 
        {
            return _items; // _items kan NIET naar ICollection<object> gecast worden
        }
    }

}


En andere oplossing dan iets om _items heen-wrappen wat ICollection<object> implementeert zie ik niet. Heeft iemand een goede oplossing voor dit probleem?

[ Voor 4% gewijzigd door Verwijderd op 11-01-2008 10:36 . Reden: code tags ]


Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 10-08 02:59

Gerco

Professional Newbie

Logisch toch? Het is geen ICollection<object>, want dat zou betekenen dat de consumer van je Items property zoiets kan doen:
C#:
1
2
3
MyInterface my = new MyImplementation<someType>();
ICollection<object> items = my.Items;
items.add("some string");


En dat kan natuurlijk niet, want je items is een ICollection<someType> en niet een ICollection<object>.

PS. Gebruik [code=c#][/] tags, dan is je code een stuk leesbaarder.

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Nu online
Maak je interface zo:
code:
1
2
3
4
IMyInterface<T>
{
   ICollection<T> Items { get; }
}

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op vrijdag 11 januari 2008 @ 10:52:
Maak je interface zo:
code:
1
2
3
4
IMyInterface<T>
{
   ICollection<T> Items { get; }
}
Ik zou afraden generic interfaces te gebruiken. Het punt is nl, dat interfaces al een generic manier van programmeren is, en als je generics toevoegt aan de interface heb je veelal casting problemen verderop in je code omdat je het type van T niet weet. Met interfaces kun je juist generic types gebruiken ZONDER T te weten op dat punt en dat komt soms voor.

Waar TS tegenaanloopt heet co/contra variance. Dit is wel gesupport door de CLR maar niet door C#/VB.NET.

Co/contra variance is wel aanwezig op arrays:
string[] strings = new string[2] {"Aap", "Noot"};
object[] = (object[])strings;

dit compileert, terwijl dit eigenlijk niet kan want ofschoon string een subtype van object is, is een ARRAY van strings niet een subtype van een ARRAY van objects. Co/contra variance support maakt het mogelijk die cast toch te maken.

Voor non-arrays is dit echter niet gesupport. Dus List<string> is geen subtype van List<object> ofschoon string een subtype is van object.

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


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor jullie reacties. Even wat verduidelijken: De code is overigens slechts een voorbeeld om het probleem te illustreren. De interface moet absoluut niet generic worden. Oa om de redenen die EfBe geeft.

Dat het casten niet mogelijk is klopt, zie ook reactie EfBe.

Het probleem wat ik probeer op te lossen is:

hoe deze interface in een generic implementatie class zo netjes/goed mogelijk te implementeren

De beste oplossing die ik tot nu toe heb is een wrapper class te schrijven zoals in de openingspost beschreven. Ik hoop echter dat ik iets over het hoofd zie, en dat er een mooiere oplossing is.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Nu online
Maar, hoe los je het probleem van de topicstarter dan op ?
Als hij in z'n interface wil vastleggen dat z'n type een collectie items van een bepaald type moet kunnen returnen ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • bigbeng
  • Registratie: Augustus 2000
  • Laatst online: 26-11-2021
Noem me simpel, maar waarom uberhaupt proberen een ICollection<T> aan te maken? Zit het nut daarvoor in code die je hier niet laat zien? Je wilt type-safe, maar dat kun je toch ook afdwingen in de methodes die verantwoordelijk zijn voor het manipuleren van je collection?

Mijns inziens maak je of de interface ook generic (wat blijkbaar een slecht idee is), of je laat je interne ICollection<T> member variabele varen.

Acties:
  • 0 Henk 'm!

  • Xiphalon
  • Registratie: Juni 2001
  • Laatst online: 14-09 12:44
code:
1
ICollection<T> _items

vervangen door
code:
1
ICollection<object> _items

geen optie?

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
darkmage schreef op vrijdag 11 januari 2008 @ 12:53:
code:
1
ICollection<T> _items

vervangen door
code:
1
ICollection<object> _items

geen optie?
Nope. Ik wil in m'n implementatie (intern!) type-safety. Dit heeft tot voordeel... type-safety :*) en bovendien scheelt het performance (niet hoeven casten). Extra checks bij het bijv toevoegen va items zijn dan ook niet nodig. Intern alle voordelen van generics dus.

Aan de buitenkant wil ik een minder-specifieke (abstractere) interface.

Volgens mij is dit een vrij normaal design, alleen ben ik dus zoekende naar hoe het beste de implementatie doen. M'n huidige oplssing heb ik namelijk niet een 100% goed gevoel bij.

Acties:
  • 0 Henk 'm!

  • bigbeng
  • Registratie: Augustus 2000
  • Laatst online: 26-11-2021
Tenzij je van de co/contravariance van de CLR gebruik kunt maken zoals EfBe als beschrijft, lijkt het me niet mogelijk om dit te regelen zonder een nieuwe ICollection<T> implementatie toe te voegen. Of anders de get de collection te laten omzetten naar 1 van het juiste type. Maar dan ben je je typesafety weer kwijt.

Je noemt het vrij normaal, maar dat is het alleen zonder generics. Je doorsnijdt hiermee namelijk de overervingsstructuur zoals EfBe ook al aangeeft. Blijkbaar kan de CLR het wel aan, maar ik kan mij niet voorstellen dat een dergelijke cast niet een performance penalty met zich meebrengt.

Ik neem aan dat jij wil dat ondanks het feit dat hij naar een ICollection<object> gecast is, er nog steeds alleen maar objecten van het type T bijgestopt mogen worden? Dat is volgens mij oneigenlijk gedrag van een ICollection<object> object.

Type-safety is leuk, maar het is niet de heilige graal. Als je netjes test, komen structurele problemen, vanzelf aan het licht, ook al worden ze niet compile-time opgemerkt.
Pagina: 1