[C#] Generic constraints (java "super" keyword )

Pagina: 1
Acties:
  • 146 views sinds 30-01-2008
  • Reageer

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
Ik had het laatst met iemand over de generics in C# vs Java. Nou hadden we het er over dat je in java een Super keyword hebt en in C# volgens mij niks vergelijkbaars. In eerste instantie kon ik ook niet zo goed bedenken wanneer je het nou echt nodig zou hebben maar ik ben toch wel benieuwd hoe jullie bijvoorbeeld het volgende stukje aan zouden pakken

C#:
1
2
3
4
5
6
7
8
9
10
11
12
public class GenericClass<T>
{
    private ICollection<T> col;

    public void CopyTo<U>(ICollection<U> collection) where T : U
    {
        foreach( T t in col )
        {
            collection.Add(t);
        }
    }
}

Wat ik hier wil doen is dus alle items in mijn collection van T kopieren naar een collection van U. Om dit mogenlijk te maken geef ik aan dat U een superclass van T moet zijn. De constraint die ik opgeef is echter niet toe gestaan in C#. In java zou je voor zo'n geval bijvoorbeeld het super keyword gebruiken.

Op het moment dat je alle classes zelf maakt zou je het natuurlijk gewoon kunnen zorgen dat in ICollection een AddRange methode zit die een ICollection<T> accepteerd. Maar hoe zou je dit oplossen als je die classes niet in je beheer hebt en je wilt toch iets dergelijks doen?

“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.”


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Om dit mogenlijk te maken geef ik aan dat U een superclass van T moet zijn.
Geef je daar niet aan dat T een superclass moet zijn van U ? Maw, dat T inherit van U, en dat U dus een
subclass is ?

In C# doe je het zo:
code:
1
public class GenericClass<T> where T : U

De constraint bepaal je dus op class - niveau, en niet op method niveau.

https://fgheysels.github.io/


  • martennis
  • Registratie: Juli 2005
  • Laatst online: 16-01 14:17
doe je dat in java niet met de instanceof operator?
daarmee kun je kijken of een klasse al dan niet van de opgegeven klasse wordt overgeerft

beetje kryptisch, dus maar ff een linkje

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
whoami schreef op dinsdag 01 augustus 2006 @ 13:21:
[...]

Geef je daar niet aan dat T een superclass moet zijn van U ? Maw, dat T inherit van U, en dat U dus een
subclass is ?
Nee dan stond er U : T. Nu staat er dat U een superclass moet zijn van T
In C# doe je het zo:
code:
1
public class GenericClass<T> where T : U

De constraint bepaal je dus op class - niveau, en niet op method niveau.
Maar op class niveau is de Type parameter U toch nog niet bekend dus daar kan ik de constraint nog niet zetten. Pas bij de methode introduceer ik de Type parameter U. Ik geef met die constraint inderdaad aan dat T U moet extenden of implementeren. Maar aangezien T al vastligt betekend het dus dat U een superclass van T moet zijn.
martennis schreef op dinsdag 01 augustus 2006 @ 13:24:
doe je dat in java niet met de instanceof operator?
daarmee kun je kijken of een klasse al dan niet van de opgegeven klasse wordt overgeerft

beetje kryptisch, dus maar ff een linkje
De instanceof operator gebruik je alleen op een instance ( in C# is dat de is operator ) en daar heb je met Generics dus niet zo veel aan. Het is ook niet het probleem om runtime te controleren of iets van het goede type is. Het probleem is de definitie van de Generic types

[ Voor 68% gewijzigd door Woy op 01-08-2006 13:29 ]

“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.”


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
whoami schreef op dinsdag 01 augustus 2006 @ 13:21:
[...]

Geef je daar niet aan dat T een superclass moet zijn van U ? Maw, dat T inherit van U, en dat U dus een
subclass is ?
Als T van U inherit (overerft dus), dan is T toch de subclass en U de superclass?

Noushka's Magnificent Dream | Unity


  • Riegstar
  • Registratie: Februari 2003
  • Niet online

Riegstar

Wadapatja!

Java: instanceof
C#: is

Java: super
C# base

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
Riegstar schreef op dinsdag 01 augustus 2006 @ 13:28:
Java: instanceof
C#: is

Java: super
C# base
Ja de keywords ken ik allemaal wel maar ik heb het hier over het super keyword i.c.m. generics die heeft een andere betekenis als het gewone super keyword.

“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.”


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Michali schreef op dinsdag 01 augustus 2006 @ 13:26:
[...]

Als T van U inherit (overerft dus), dan is T toch de subclass en U de superclass?
Eh, ja, ik was nog niet goed wakker. 8)7
Maar op class niveau is de Type parameter U toch nog niet bekend dus daar kan ik de constraint nog niet zetten. Pas bij de methode introduceer ik de Type parameter U. Ik geef met die constraint inderdaad aan dat T U moet extenden of implementeren. Maar aangezien T al vastligt betekend het dus dat U een superclass van T moet zijn.
Hm, heb ik ook niet goed gekeken.

[ Voor 43% gewijzigd door whoami op 01-08-2006 13:56 ]

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

rwb schreef op dinsdag 01 augustus 2006 @ 13:16:
Ik had het laatst met iemand over de generics in C# vs Java.
O-)
whoami schreef op dinsdag 01 augustus 2006 @ 13:21:

Geef je daar niet aan dat T een superclass moet zijn van U ? Maw, dat T inherit van U, en dat U dus een subclass is ?
Natuurlijk niet: class Aap : Dier. Aap is nu een subclass van Dier.
In het voorbeeld van rwb wil je in je CopyTo methode dat je een collection meekrijgt waar een T aan toegevoegd mag worden. Dus dat moet een Collection<U> zijn, waar U=T, of U een superclass is van T (aan een collection van U=Object mag je een T=String toevoegen). Helaas staat .Net alleen subclass constraints toe, waardoor je de CopyTo nooit netjes kunt implementeren - alternatieven zijn idd de AddFrom op de andere instance implementeren zodat je de constraints omdraait, of elke Collection<U> accepteren (dus zonder constraint) en dan tijdens runtime controleren of het wel klopt. De eerste oplossing is natuurlijk de mooiste, maar lang niet altijd mogelijk.
Riegstar schreef op dinsdag 01 augustus 2006 @ 13:28:
Java: instanceof
C#: is

Java: super
C# base
le-zen

[ Voor 8% gewijzigd door .oisyn op 01-08-2006 13:58 ]

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.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hmm, kun je trouwens geen helper class implementeren, zodat je de constraints om kan draaien?

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class GenericClass<T> 
{ 
    private ICollection<T> col; 

    public void CopyTo<U>(ICollection<U> collection) where T : U 
    { 
        GenericClassHelper<U>.Copy(col, collection);
    } 
}

class GenericClassHelper<T>
{
    public static void Copy<U>(ICollection<U> src, ICollection<T> dest) where U : T
    {
        foreach(U u in src) 
        { 
            dest.Add(u); 
        }         
    }
}


.edit: bliep nee, je kan nog altijd niet de juiste compile-time constraint leggen op de CopyTo functie. Wat gebeurt er eigenlijk als je de CopyTo hier zonder constraint definieert en 'm met 'onjuiste' parameters aanroept?

[ Voor 19% gewijzigd door .oisyn op 01-08-2006 14:07 ]

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.


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Het lijkt me toch dat voor deze class T altijd een subclass moet zijn voor U om CopyTo te implementeren? Zou dit dan niet werken zo:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
public class GenericClass<T> where T : U
{
    private ICollection<T> col;

    public void CopyTo<U>(ICollection<U> collection)
    {
        foreach( T t in col )
        {
            collection.Add(t);
        }
    }
}

Ik moet zeggen dat ik nog weinig met generics heb gedaan, maar naar mijn eigen logica zou dit wel beter zijn. Als dit niet goed is, zou je dan kunnen uitleggen waarom niet, dan begrijp ik dat ook beter.

Noushka's Magnificent Dream | Unity


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, je legt hier een constraint aan de hand van een type dat nog lang niet bekend is tijdens de definitie van je class (de U wordt pas later gedefinieerd) en bovendien niet constant is (elke methode kan z'n eigen U definieren)

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.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
.oisyn schreef op dinsdag 01 augustus 2006 @ 14:04:
Hmm, kun je trouwens geen helper class implementeren, zodat je de constraints om kan draaien?

C++:
1
    public void CopyTo<U>(ICollection<U> collection) where T : U 
Nee dus ;)
edit:

ow dat had je ook al door


Je zou het idd op kunnen lossen door gewoon elke ICollection van U te accepteren en dan runtime te controleren of dat klopt. Het nadeel is dat je volgens mij niet kunt kasten naar een Type paramter dus je kunt niet het volgende doen

C#:
1
2
3
4
5
6
7
8
public void CopyTo<U>(ICollection<U> collection)
{
    if( !typeof( T ).IsSubClassOff( typeof(U ) )
        throw new ApplicationException();

    T t;
    collection.Add( (U)t ); //Hier krijg je dus een compiler fout omdat je niet naar 'U' kunt casten
}

[ Voor 47% gewijzigd door Woy op 01-08-2006 14:13 ]

“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.”


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
.oisyn schreef op dinsdag 01 augustus 2006 @ 14:07:
Nee, je legt hier een constraint aan de hand van een type dat nog lang niet bekend is tijdens de definitie van je class (de U wordt pas later gedefinieerd) en bovendien niet constant is (elke methode kan z'n eigen U definieren)
Ah, natuurlijk. Je kunt CopyTo natuurlijk met iedere waarde aanroepen, zolang die aan je constraint voldoet. (Althans dat wil rwb en lukt niet, vandaar dit topic :P)

Noushka's Magnificent Dream | Unity


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

rwb schreef op dinsdag 01 augustus 2006 @ 14:08:
Je zou het idd op kunnen lossen door gewoon elke ICollection van U te accepteren en dan runtime te controleren of dat klopt. Het nadeel is dat je volgens mij niet kunt kasten naar een Type paramter dus je kunt niet het volgende doen
Waarom kun je niet casten? Anyway, daar werkt die helper class dan weer wel voor.

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.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
Michali schreef op dinsdag 01 augustus 2006 @ 14:16:
[...]

Ah, natuurlijk. Je kunt CopyTo natuurlijk met iedere waarde aanroepen, zolang die aan je constraint voldoet. (Althans dat wil rwb en lukt niet, vandaar dit topic :P)
Idd. In java kan je het bijvoorbeeld zo doen
Java:
1
2
3
public void CopyTo(ICollection<? super T> collection)
{
}

Op die manier kan je alle Collections meegeven waar je T's in kunt stoppen.
.oisyn schreef op dinsdag 01 augustus 2006 @ 14:23:
[...]

Waarom kun je niet casten? Anyway, daar werkt die helper class dan weer wel voor.
Het is nou eenmaal niet mogenlijk om te casten met een Type parameter. Je kan alleen casten met een type-name. Hoe zou je dat dan oplossen met een helper class? Want ook in de helper class kan je niet opeens de type-name te voorschijn toveren.

Dit is volgens mij niet mogenlijk
C#:
1
2
3
4
public TOutput Convert<TInput, TOutput>( TInput input )
{
    return (TOutput)input;
}

dat zou alleen kunnen als je specificeerd "where TInput : TOutput" maar daar heb je weer niks aan aangezien je dat niet af kunt dwingen in je CopyTo mehode

[ Voor 14% gewijzigd door Woy op 01-08-2006 14:44 ]

“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.”


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

rwb schreef op dinsdag 01 augustus 2006 @ 14:40:
Het is nou eenmaal niet mogenlijk om te casten met een Type parameter. Je kan alleen casten met een type-name. Hoe zou je dat dan oplossen met een helper class? Want ook in de helper class kan je niet opeens de type-name te voorschijn toveren.
Hmm ok, ik dacht dat je je type parameters gewoon als typenames kon gebruiken. Dit moet toch ook kunnen:
C#:
1
2
3
4
void foo<T> (T t)
{
    T t2 = t;
}


* .oisyn slingert z'n vs 2005 eens aan

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.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
.oisyn schreef op dinsdag 01 augustus 2006 @ 14:46:
[...]

Hmm ok, ik dacht dat je je type parameters gewoon als typenames kon gebruiken. Dit moet toch ook kunnen:
C#:
1
2
3
4
void foo<T> (T t)
{
    T t2 = t;
}


* .oisyn slingert z'n vs 2005 eens aan
Ja dat kan idd wel. Maar als het om Casten gaat kan dat dus niet. Je kan trouwens wel de 'as' operator gebruiken maar dan ben je wel verplicht om bij je type parameter de contraint te zetten dat het een refference type is.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class GenericClass<T>
{
    private ICollection<T> col;

    public void CopyTo<U>(ICollection<U> collection) where U : class
    {
        if( !typeof(T).IsSubclassOf( typeof(U) ) )
            throw new ApplicationException();

        foreach( T t in col )
        {
            U u = t as U;
            collection.Add(u);
        }
    }
}

zou dus wel kunnen. Maar echt netjes is het niet vindt ik.

[ Voor 29% gewijzigd door Woy op 01-08-2006 15:21 ]

“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.”


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik ontdek trouwens een mooie bug in de C++/CLI compiler tijdens het testen :P

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
generic<class T> ref class MyGeneric
{
};

generic<class U> ref class GenericHelper
{
public:
    generic<class T> static void Foo(MyGeneric<T> ^ a, MyGeneric<U> ^ b)
    {
    }
};

generic<class T> ref class MyClass
{
    MyGeneric<T> ^ a;

public:
    generic<class U> void Foo(MyGeneric<U> ^ b)
    {
        GenericHelper<U>::Foo<T>(a, b);
    }
};

Error op regel 20: error C2670: 'GenericHelper<U>::Foo' : the function template cannot convert parameter 2 from type 'MyGeneric<T> ^'
Als ik de <T> er weg haal zegt ie ook dat T ambiguous is en dat de signature van de functie blijkbaar Foo<MyGeneric<T>^, MyGeneric<T>^> is 8)7. Deze ga ik even reporten :)

.edit: en gedaan

[ Voor 7% gewijzigd door .oisyn op 01-08-2006 16:12 ]

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.


  • EfBe
  • Registratie: Januari 2000
  • Niet online
C#'s restricties zijn niet zo slim in elkaar gezet, dat neemt niet weg dat het op zich best wel werkt af op dit soort ranzigheid na dan natuurlijk :).

(edit) oisyn: voted :) Als jij nou even op mijn bug vote ;)

[ Voor 34% gewijzigd door EfBe op 01-08-2006 22:24 ]

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13-02 18:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

done ;)

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.

Pagina: 1