[.NET] Waarom mag dit niet (inheritance)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Wijnbo
  • Registratie: December 2002
  • Laatst online: 06-09 20:35

Wijnbo

Electronica werkt op rook.

Topicstarter
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
using System.Collections.Generic;

namespace ClassLibrary1
{
    public class Class1
    {

        public A AnA { get; set; }
        public A[] AnAArray { get; set; }
        public List<A> AListOfA { get; set; }

        public Class1()
        {
            AnA = new A();
            AnA = new B();

            AnAArray = new[] { new A(), new B(), new A() };
            AnAArray = new[] { new B(), new B(), new B() };

            AListOfA = new List<A> {new B()};

            AListOfA = new List<B>();
        }

        public class A{}
               
        public class B : A {}
    }
}


Ik krijg een fout op:
C#:
1
            AListOfA = new List<B>();

Waarom mag de rest wel, en snapt .NET niet dat een List<B> alleen maar elementen bevat die in ieder geval A als basisklasse hebben, en het dus eigenlijk een lijst van <A> elementen is?

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
De compiler kijkt gewoon of de types voor die generics hetzelfde zijn. Er is ook geen enkele reden te doen wat jij wil. Het kan ook gewoon niet omdat zo'n generic list ook waarden van type T teruggeeft. Als je probeert een List<X> instantie te propen in een List<T> referentie weet de compiler niet of je nu als returnwaarden uit die list een X of een T object wil.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Wijnbo
  • Registratie: December 2002
  • Laatst online: 06-09 20:35

Wijnbo

Electronica werkt op rook.

Topicstarter
Ben ik deels wel met je eens, maar dan zou je ook kunnen redeneren dat je voor je een nieuwe instantie van B in een List<A> kunt proppen, je deze eerst zou moeten typecasten naar A. Immers, je hebt een lijst van A's en je krijgt ook een lijst van A's terug.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Dat maak je een lijst zo aan: Lijst<A> lijst = new List<A>();

Daar kan je dan naar hartelust B's instoppen en de compiler weet dat je bij lijst.get(0) een A verwacht en geen B :)

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Wijnbo
  • Registratie: December 2002
  • Laatst online: 06-09 20:35

Wijnbo

Electronica werkt op rook.

Topicstarter
Hydra schreef op dinsdag 30 maart 2010 @ 10:50:
Dat maak je een lijst zo aan: Lijst<A> lijst = new List<A>();

Daar kan je dan naar hartelust B's instoppen en de compiler weet dat je bij lijst.get(0) een A verwacht en geen B :)
Zo ver was ik ook inmiddels ;) Ik vroeg me alleen af waarom het niet kan. Ik bedoel, met een array kan het wel. Nu weet ik dat een array iets anders werkt, maar het principe is het zelfde.

Acties:
  • 0 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

B erft wel over van A maar List<B> niet van List<A>.

Dit is covariance met generics. Dit gaat vanaf 4.0 (enkel met interfaces).

Zie ook dit topic: \[C# / .NET 3.5] Downcasten in generic lists.

[ Voor 28% gewijzigd door Snake op 30-03-2010 10:56 ]

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Covariance is het keyword waar je op wil zoeken.

Het probleem is dat een List<B> wat anders is dan een List<A>. Als je hetvolgende stukje code bekijkt snap je misschien waarom het niet typesafe zou zijn als je zomaar zou kunnen Casten
C#:
1
2
3
List<B> listOfB = new List<B>();
List<A> listOfA = listOfB;
listOfA.Add( new A() );

Als dat zou compilen is het het dus mogelijk om een A in een collectie van type B te stoppen, en dat wil je natuurlijk niet, want in een List<B> mogen alleen B's en types die van B inheritten
offtopic:
edit:
Grrr, trapt Snake
en zwaait naar Janoz ;)

[ Voor 4% gewijzigd door Woy op 30-03-2010 10:58 ]

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

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 20:06

Janoz

Moderator Devschuur®

!litemod

Eigenlijk heel simpel. Stel dat het zou kunnen.

C#:
1
2
3
4
5
6
7
8
9
10
List<A> AListOfA;
List<B> AListOfB = new List<B>();

//nu de toekenning 
AListOfA = AListOfB;

//Dan zou dit moeten kunnen
AListOfA.add(new A());

// KRAK... nu zou er dus een object A in AListOfB zitten.



edit: ... hmmm... spuit 34782947

[ Voor 6% gewijzigd door Janoz op 30-03-2010 10:57 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Wijnbo
  • Registratie: December 2002
  • Laatst online: 06-09 20:35

Wijnbo

Electronica werkt op rook.

Topicstarter
Snake en Woy en janoz, bedankt. Volledig duidelijk zo, vooral het voorbeeld met de cast ;)

[ Voor 10% gewijzigd door Wijnbo op 30-03-2010 10:58 ]


Acties:
  • 0 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Het is wel jammer dat ze IList<T> niet covariant hebben gemaakt.

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Het kan ook met .NET 2.0 en 3.x. Alleen moet je dan niet A en B gebruiken, maar van A een interface extraheren en deze interface als generic gebruiken:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IEntity
{
    int ID { get; }
    string Name { get; }
}

public class A : IEntity {}
public class B : A
{
   public bool Active { get; set; }
}

List<IEntity> entities = new List(IEntity)();
entities.Add(new A { ID=2, Name="A" });
entities.Add(new B  { ID=3, Name="B", Active=false });

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Niemand_Anders schreef op dinsdag 30 maart 2010 @ 12:01:
Het kan ook met .NET 2.0 en 3.x. Alleen moet je dan niet A en B gebruiken, maar van A een interface extraheren en deze interface als generic gebruiken:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IEntity
{
    int ID { get; }
    string Name { get; }
}

public class A : IEntity {}
public class B : A
{
   public bool Active { get; set; }
}

List<IEntity> entities = new List(IEntity)();
entities.Add(new A { ID=2, Name="A" });
entities.Add(new B  { ID=3, Name="B", Active=false });
Je kan dan ook gewoon de interface weglaten en gewoon een List<A>() maken natuurlijk. Dit is IMHO geen reden om een interface te introduceren.

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

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 15-09 13:58

mOrPhie

❤️❤️❤️❤️🤍

Overigens, een tikkeltje terzijde, maar dit is wel interessant om te kijken mbt covariance en contravariance in .NET 4:

http://channel9.msdn.com/...Contravariance-in-NET-40/

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


Acties:
  • 0 Henk 'm!

  • _Noldy
  • Registratie: September 2009
  • Laatst online: 06-07 14:33
Wijnbo schreef op dinsdag 30 maart 2010 @ 10:38:
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
using System.Collections.Generic;

namespace ClassLibrary1
{
    public class Class1
    {

        public A AnA { get; set; }
        public A[] AnAArray { get; set; }
        public List<A> AListOfA { get; set; }

        public Class1()
        {
            AnA = new A();
            AnA = new B();

            AnAArray = new[] { new A(), new B(), new A() };
            AnAArray = new[] { new B(), new B(), new B() };

            AListOfA = new List<A> {new B()};

            AListOfA = new List<B>();
        }

        public class A{}
               
        public class B : A {}
    }
}


Ik krijg een fout op:
C#:
1
            AListOfA = new List<B>();

Waarom mag de rest wel, en snapt .NET niet dat een List<B> alleen maar elementen bevat die in ieder geval A als basisklasse hebben, en het dus eigenlijk een lijst van <A> elementen is?
Omdat je in een knikkerzak geen koeien kan stoppen. Je kan in een blokkendoos met een vierkant gat ook geen driehoek stoppen. Mits de driehoek klein genoeg is, dan zou er eventueel sprake kunnen zijn van Abstractie, erving etc... Maar dat is hier niet het geval.
Pagina: 1