Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[.NET]Covariance & contravariance

Pagina: 1
Acties:

  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
afgesplitst van De Devschuur Coffee Corner - Iteratie 7

...
Waarom kan je dit niet doen:
C#:
1
2
3
4
5
6
7
8
public class Foo<T> where T : Bar {}
public class Bar {}
public class ZBar : Bar {};

/**/

Foo<ZBar> zbarFoo = new Foo<ZBar>();
var barFoo = (Foo<Bar>) zbarFoo; // dit kan niet


Je zou toch zeggen dat je dat wel kan casten aangezien het een parent is en je dus prima weet dat een cast kan.....

[ Voor 11% gewijzigd door Woy op 21-10-2014 08:50 ]

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI


  • RobertMe
  • Registratie: Maart 2009
  • Laatst online: 23:13
F.West98 schreef op zondag 19 oktober 2014 @ 16:28:
...
Waarom kan je dit niet doen:
C#:
1
2
3
4
5
6
7
8
public class Foo<T> where T : Bar {}
public class Bar {}
public class ZBar : Bar {};

/**/

Foo<ZBar> zbarFoo = new Foo<ZBar>();
var barFoo = (Foo<Bar>) zbarFoo; // dit kan niet


Je zou toch zeggen dat je dat wel kan casten aangezien het een parent is en je dus prima weet dat een cast kan.....
Als je een methode hebt die T als param heeft kan dat niet. Want dan zou je ineens Bar instances kunnen meegeven als param van die method, terwijl die instance niet alleen met ZBar kan werken.

Op het moment dat Foo geen methods bevat met een param T, kun je de generic definieren als Foo<out T>, dan mag het wel, maar mag je T ook alleen als return gebruiken (en als out param? maar dat weet ik niet 100% zeker).

  • Feanathiel
  • Registratie: Juni 2007
  • Niet online

Feanathiel

Cup<Coffee>

F.West98 schreef op zondag 19 oktober 2014 @ 16:28:
...
Waarom kan je dit niet doen:
C#:
1
2
3
4
5
6
7
8
public class Foo<T> where T : Bar {}
public class Bar {}
public class ZBar : Bar {};

/**/

Foo<ZBar> zbarFoo = new Foo<ZBar>();
var barFoo = (Foo<Bar>) zbarFoo; // dit kan niet


Je zou toch zeggen dat je dat wel kan casten aangezien het een parent is en je dus prima weet dat een cast kan.....
Omdat het niet altijd opgaat:

C#:
1
2
3
List<Dog> dogs = new List<Dog>();
var animals = (List<Animal>) dogs;
animals.Add(new Cat()); // ?

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22:57
F.West98 schreef op zondag 19 oktober 2014 @ 16:28:
Waarom kan je dit niet doen: [knip]
Ik doe geen C#, maar volgens TFM kan dat wel als je die parameter expliciet als covariant declareert.

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:32

RayNbow

Kirika <3

Soultaker schreef op zondag 19 oktober 2014 @ 17:04:
[...]

Ik doe geen C#, maar volgens TFM kan dat wel als je die parameter expliciet als covariant declareert.
Maar dat moet dan wel in een interface. :)

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
F.West98 schreef op zondag 19 oktober 2014 @ 16:28:
...
Waarom kan je dit niet doen:
C#:
1
2
3
4
5
6
7
8
public class Foo<T> where T : Bar {}
public class Bar {}
public class ZBar : Bar {};

/**/

Foo<ZBar> zbarFoo = new Foo<ZBar>();
var barFoo = (Foo<Bar>) zbarFoo; // dit kan niet


Je zou toch zeggen dat je dat wel kan casten aangezien het een parent is en je dus prima weet dat een cast kan.....
Covariance en Contravariance in generics. Zat over te vinden. Het was voor .net 4.0 nog stricter. In 4.0 kan het wel alleen zijn er nog steeds beperkingen.

Maar er is genoeg over te vinden als je zoekt op bovenstaande termen.

  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
8 :)

En de oplossing bleek simpel (bedankt voor de tips!), een ICovariant interface met out R, die implementeren in mijn Collection-class, en nu op één plek nog een beetje een dirty cast (van ICovariant<...> naar ...Collection<....>, maar die Collection is de enige class die ICovariant implementeert)

[ Voor 97% gewijzigd door F.West98 op 19-10-2014 23:43 ]

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI


  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:32

RayNbow

Kirika <3

F.West98 schreef op zondag 19 oktober 2014 @ 23:42:
En de oplossing bleek simpel (bedankt voor de tips!), een ICovariant interface met out R, die implementeren in mijn Collection-class, en nu op één plek nog een beetje een dirty cast (van ICovariant<...> naar ...Collection<....>, maar die Collection is de enige class die ICovariant implementeert)
Waarom heb je nog steeds een cast nodig? Zou je dan niet gewoon meer methoden in je interface moeten opnemen? :?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 19-11 18:15

Sebazzz

3dp

Een collection kan je niet maken met Covariance / contravariance.

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


  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
RayNbow schreef op maandag 20 oktober 2014 @ 06:08:
[...]

Waarom heb je nog steeds een cast nodig? Zou je dan niet gewoon meer methoden in je interface moeten opnemen? :?
Omdat eh... de code een beetje apart is opgezet:
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
internal interface ICovariant<out R> {}
public class SomeCollection<T> : ICollection<T>, ICovariant<T> where T : SomeObject {
    private readonly List<T> items = new List<T>();
    
    public void Remove(T item) {
        item.TryRemoveFromCollection(this); // Yeah, right
    }

    internal void RemoveInternal(T item) {
        items.Remove(item);
    }
    /* Meer remove/copy/add functies */
}

public class SomeObject {
    private List<ICovariant<SomeObject>> collections = new List<ICovariant<SomeObject>>();

    internal void TryRemoveFromCollection<T>(SomeCollection<T> collection) where T : SomeObject {
        // Iets met locks
        collections.Remove(collection); // Hiervoor had ik dus de Covariant nodig (toch?)
        collection.RemoveInternal((T) this);
    }

    // So far, so good. Dan iets met state management enzo, en op het moment dat SomeObject verwijderd kan worden:
    internal void TryRemoveFromAllCollections() {
        // Weer locks
        foreach(var collection in collections)
            ((SomeCollection<SomeObject>) collection).RemoveInternal(this); // anders kan je die method niet bereiken. Die method valt niet te definiëren in de ICovariant, (want R herbruiken kan niet)
        collections = null;
    }
}


Die opzet met de class zichzelf laten toevoegen is btw niet mijn idee, vraag maar aan MS waarom ze dat zo doen :+
(en sorry voor de enorme hoeveelheid code)

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI


  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:32

RayNbow

Kirika <3

F.West98 schreef op maandag 20 oktober 2014 @ 17:01:
[...]

Omdat eh... de code een beetje apart is opgezet:
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
internal interface ICovariant<out R> {}
public class SomeCollection<T> : ICollection<T>, ICovariant<T> where T : SomeObject {
    private readonly List<T> items = new List<T>();
    
    public void Remove(T item) {
        item.TryRemoveFromCollection(this); // Yeah, right
    }

    internal void RemoveInternal(T item) {
        items.Remove(item);
    }
    /* Meer remove/copy/add functies */
}

public class SomeObject {
    private List<ICovariant<SomeObject>> collections = new List<ICovariant<SomeObject>>();

    internal void TryRemoveFromCollection<T>(SomeCollection<T> collection) where T : SomeObject {
        // Iets met locks
        collections.Remove(collection); // Hiervoor had ik dus de Covariant nodig (toch?)
        collection.RemoveInternal((T) this);
    }

    // So far, so good. Dan iets met state management enzo, en op het moment dat SomeObject verwijderd kan worden:
    internal void TryRemoveFromAllCollections() {
        // Weer locks
        foreach(var collection in collections)
            ((SomeCollection<SomeObject>) collection).RemoveInternal(this); // anders kan je die method niet bereiken. Die method valt niet te definiëren in de ICovariant, (want R herbruiken kan niet)
        collections = null;
    }
}


Die opzet met de class zichzelf laten toevoegen is btw niet mijn idee, vraag maar aan MS waarom ze dat zo doen :+
(en sorry voor de enorme hoeveelheid code)
Hoe wil je SomeObject en SomeCollection<T> precies gebruiken?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
SomeObject is een WebSocketHandler (met verder functies om dingen over de verbinding te sturen) en die moet je extenden om je eigen functionaliteit te bieden. De Collection wordt static gebruikt om de connections te behouden. Zie ook hier:
http://blogs.msdn.com/b/y...ebapi-and-websockets.aspx (codevoorbeeld)

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI


  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33

HMS

Die code is wel een goede kandidaat voor TheDailyWTF :+

ARGH, leuke foutmelding: 'some dependencies were not satisfied.' Ja uhh, welke dan? man man man

[ Voor 5% gewijzigd door HMS op 20-10-2014 18:41 ]


  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:32

RayNbow

Kirika <3

F.West98 schreef op maandag 20 oktober 2014 @ 18:14:
SomeObject is een WebSocketHandler (met verder functies om dingen over de verbinding te sturen) en die moet je extenden om je eigen functionaliteit te bieden. De Collection wordt static gebruikt om de connections te behouden.
Maar gebruik je SomeCollection<T> ook voor verschillende T's of is T altijd gelijk aan SomeObject?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
RayNbow schreef op maandag 20 oktober 2014 @ 19:03:
[...]

Maar gebruik je SomeCollection<T> ook voor verschillende T's of is T altijd gelijk aan SomeObject?
T is atm enkel nog gelijk aan een derived class van SomeObject, maar misschien ga ik later nog een derived class maken (daarom wou ik die T in de eerste plaats, voordat ik de <T> had toegevoegd ging hij ervan uit dat alles SomeObject was)

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI


  • Korben
  • Registratie: Januari 2001
  • Laatst online: 14-11 13:15

Korben

() => {};

F.West98 schreef op maandag 20 oktober 2014 @ 19:35:
[...]

T is atm enkel nog gelijk aan een derived class van SomeObject, maar misschien ga ik later nog een derived class maken (daarom wou ik die T in de eerste plaats, voordat ik de <T> had toegevoegd ging hij ervan uit dat alles SomeObject was)
Waarom gebruik je niet een niet-generic versie van ICollection<T>, namelijk IList?

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
public class SomeCollection<T>: ICollection<T>, IList
    where T: SomeObject
{
    private readonly List<T> _items = new List<T>();
    
    public bool Remove(T item)
    {
        return item.RemoveFromCollection(this);
    }
    
    void IList.Remove(object item)
    {
        _items.Remove((T) item);
    }
    
    // meer methods
}

public class SomeObject
{
    private readonly List<IList> _collections = new List<IList>();

    internal bool RemoveFromCollection(IList collection)
    {
        collection.Remove(this);
        return _collections.Remove(collection);
    }
}

.oisyn: Échte programmeurs haten PHP met een passie. Ben jij soms geen echte programmeur?


  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
1) Het zijn geen lists (de Collection bevat een ConcurrentDictionary<T, int> en de Handler bevat een HashSet)
2) RemoveInternal heeft ook nog wat extra parameters die ik hier weggelaten heb

En het werkte :+

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI


  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:32

RayNbow

Kirika <3

F.West98 schreef op maandag 20 oktober 2014 @ 19:35:
[...]

T is atm enkel nog gelijk aan een derived class van SomeObject, maar misschien ga ik later nog een derived class maken (daarom wou ik die T in de eerste plaats, voordat ik de <T> had toegevoegd ging hij ervan uit dat alles SomeObject was)
Het probleem van je code is dat het niet type-safe is. Het staat het volgende toe:

C#:
1
2
3
var xs = new SomeCollection<DerivedObject>();
var x = new SomeObject();
x.TryRemoveFromCollection(xs); // InvalidCastException

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • F.West98
  • Registratie: Juni 2009
  • Laatst online: 03:57

F.West98

Alweer 16 jaar hier

Topicstarter
Nee, die Try...-functies zijn internal en worden enkel aangeroepen uit de publieke functies Add & Remove uit SomeObject (die dus wel typesafe zijn)

Ook is die ene cast die gebruikt wordt in TryRemoveFromAllCollections, die zelfs enkel wordt aangeroepen VANUIT SomeObject op het moment dat 'ie 'af' is.

Maar ok, gaat misschien een beetje offtopic

[ Voor 41% gewijzigd door F.West98 op 20-10-2014 23:21 ]

2x Dell UP2716D | R9 7950X | 128GB RAM | 980 Pro 2TB x2 | RTX2070 Super
.oisyn: Windows is net zo slecht in commandline als Linux in GUI

Pagina: 1