[C#] Resultaat Gettype() verandert niet na cast?

Pagina: 1
Acties:

  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Eerst een stukje voorbeeld code:

C#:
1
2
3
4
5
6
7
8
public class Person {}

public class Employee : Person {}

Employee emp = new Employee();
Debug.WriteLine(emp.GetType()); //geeft Employee, prima natuurlijk
Person p = (Person) emp;
Debug.WriteLine(p.GetType()); //geeft ook Employee?!


Mijn probleem is dat ik een methode heb die een object accepteert en de naam van het type van het object gebruikt. In het geval van p moet ik dan ook 'Person' hebben en niet 'Employee'. Hoe komt het dat het runtime-type niet verandert als ik eerst cast en daarna GetType() doe? Komt dit misschien door boxing ofzo?
In ieder geval zou het zeer vervelend zijn als ik er niet achter kan komen wat het type is na de cast.

Het zelfde probleem treedt overigens ook op als je Person p as Person doet.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:56
zoepercavia schreef op 12 augustus 2003 @ 23:46:
Hoe komt het dat het runtime-type niet verandert als ik eerst cast en daarna GetType() doe?
Je hebt duidelijk wel een idee waar het over gaat, maar je begrijpt de betekenis van een cast niet goed. Met de cast geef je aan dat je het object via een andere interface wilt benaderen (als Person in plaats van Employee dus). Dat jij nu een andere interface ter beschikking hebt, maakt voor het werkelijke type van het object niet uit; het blijft een werknemer. Dat je een werknemer als persoon beschouwd, maakt niet dat die persoon opeens geen werknemer meer zou zijn.
Komt dit misschien door boxing ofzo?
Boxing heeft hier niets mee te maken.
In ieder geval zou het zeer vervelend zijn als ik er niet achter kan komen wat het type is na de cast.
Hoezo? Dat weet je toch zelf al? Jij doet die cast toch? Kun je een voorbeeld geven van een situatie waarin je denkt dat je niet weet welke interface je beschikbaar hebt?
Het zelfde probleem treedt overigens ook op als je Person p as Person doet.
Die constructie ken ik niet (ik kan eigenlijk geen C#) maar ik neem aan dat dat hetzelfde is als een cast.

Het punt is dus: een cast op een object veranderd alleen de interface die beschikbaar is; het achterliggende object blijft gewoon hetzelfde.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
Beetje raar probleem; als je weet dat een object een Employee is, weet je toch ook dat het een Person is?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • cannibal
  • Registratie: Maart 2001
  • Laatst online: 15-08 16:32
de constructie: Person p = emp as Person cast emp naar een person, behalve als emp geen person is, dan wordt p null, met een normale cast zou je een invalid cast exception krijgen.

  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Soultaker schreef op 13 augustus 2003 @ 00:56:
Hoezo? Dat weet je toch zelf al? Jij doet die cast toch? Kun je een voorbeeld geven van een situatie waarin je denkt dat je niet weet welke interface je beschikbaar hebt?
Ik gebruik de naam van het type om het object te persisteren. De interfaces van de types worden door verschillende classes gepersisteerd (EmployeeMapper, PersonMapper). EmployeeMapper roept dan bv. PersonMapper aan en die cast zelf Employee naar Person en gebruikt dan de naam van het type om de Sql op te bouwen. Maar omdat die cast dus voor het type weinig zin heeft heb ik in PersonMapper nog steeds Employee als type.
Ik zeg niet dat dit stom is van C# hoor (integendeel het is een prachtige taal), maar ik ben een beetje bang dat inheritance mapping meer problemen oplevert dan ze oplost (en dat mijn ontwerp scheuren begint te vertonen).

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
zoepercavia schreef op 13 augustus 2003 @ 08:45:
[...]


Ik gebruik de naam van het type om het object te persisteren. De interfaces van de types worden door verschillende classes gepersisteerd (EmployeeMapper, PersonMapper). EmployeeMapper roept dan bv. PersonMapper aan en die cast zelf Employee naar Person en gebruikt dan de naam van het type om de Sql op te bouwen. Maar omdat die cast dus voor het type weinig zin heeft heb ik in PersonMapper nog steeds Employee als type.
Ik zeg niet dat dit stom is van C# hoor (integendeel het is een prachtige taal), maar ik ben een beetje bang dat inheritance mapping meer problemen oplevert dan ze oplost (en dat mijn ontwerp scheuren begint te vertonen).
Ik snap het probleem nog niet echt. Als je in een Method van je PersonMapper zit dan heb je toch helemaal het type van je Person/Employee niet meer nodig. Door het feit dat je in je PersonMapper zit weet je al dat het over een Person gaat. Dat dit dan een Employee is haalt niet zoveel uit lijkt me. Dan moet je dus niet de GetType method gebruiken om je SQL op te bouwen.

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


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
zoepercavia schreef op 13 August 2003 @ 08:45:
[...]
Ik zeg niet dat dit stom is van C# hoor (integendeel het is een prachtige taal), maar ik ben een beetje bang dat inheritance mapping meer problemen oplevert dan ze oplost (en dat mijn ontwerp scheuren begint te vertonen).
Als je zorgt dat een Employee mapper alleen Employees kan persisten ( zoals je waarschijnlijk al hebt ), en dat de Persist functie van Person alleen die velden persist ( toevoegt aan het SQL statement ) die ook in Person zitten is er niets aan de hand volgens mij.

Maar volgens mij moeten we iets meer weten van je structuur ....

[ Voor 6% gewijzigd door farlane op 13-08-2003 09:31 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • EfBe
  • Registratie: Januari 2000
  • Niet online
[hier stond iets doms door slecht lezen]

[ Voor 94% gewijzigd door EfBe op 13-08-2003 10:12 ]

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


  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Het probleem zit em er een beetje in dat het bouwen van de mapper beter ging dan verwacht :) Daarom heb ik over bepaalde dingen iets minder goed nagedacht en wat meer ad hoc (wat op het eerste moment goed leek) oplossingen gebruikt.
In dit geval gaat het om het verwijderen van relaties, de code ziet er ongeveer zo uit (met veel dingen weggelaten :)):
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
public class Relation {

private Type _end1, _end2;

//verwijdert alle relaties tussen _end1 en _end2 voor domein object obj
public string GetDeleteStatement(DomainObject obj) {
return "DELETE FROM " + _relationTable + " WHERE " + obj.GetType() + "Id=?"
}
}

public class AbstractMapper {
public void DeleteRelation(Relation r, DomainObject obj) {
DB.Execute(r.GetDeleteStatement(obj);
}
}

public class PersonMapper : AbstractMapper {

public void Delete(DomainObject obj) {
Person p = (Person) obj
DeleteRelation(Relation X, obj)
}

public class EmployeeMapper : PersonMapper {
public void Delete(DomainObject obj) {
base.Delete(obj)
Employee e= (Employee) obj
}

}


Als jullie me nog kunnen volgen dan betekent dat dus dat EmployeeMapper ook de de delete van PersonMapper aanroept. Alleen de relatie die daar gedelete wordt gebeurt met het type Employee, waardoor het misgaat. Maar ik weet inderdaad al in PersonMapper dat ik met Persons werk, dus zal ik maar expliciet aan GetDeleteStatement de naam van het domein object moeten meegeven.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
zoepercavia schreef op 13 augustus 2003 @ 11:00:
Het probleem zit em er een beetje in dat het bouwen van de mapper beter ging dan verwacht :) Daarom heb ik over bepaalde dingen iets minder goed nagedacht en wat meer ad hoc (wat op het eerste moment goed leek) oplossingen gebruikt.
In dit geval gaat het om het verwijderen van relaties, de code ziet er ongeveer zo uit (met veel dingen weggelaten :)):
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
public class Relation {

private Type _end1, _end2;

//verwijdert alle relaties tussen _end1 en _end2 voor domein object obj
public string GetDeleteStatement(DomainObject obj) {
return "DELETE FROM " + _relationTable + " WHERE " + obj.GetType() + "Id=?"
}
}

public class AbstractMapper {
public void DeleteRelation(Relation r, DomainObject obj) {
DB.Execute(r.GetDeleteStatement(obj);
}
}

public class PersonMapper : AbstractMapper {

public void Delete(DomainObject obj) {
Person p = (Person) obj
DeleteRelation(Relation X, obj)
}

public class EmployeeMapper : PersonMapper {
public void Delete(DomainObject obj) {
base.Delete(obj)
Employee e= (Employee) obj
}

}


Als jullie me nog kunnen volgen dan betekent dat dus dat EmployeeMapper ook de de delete van PersonMapper aanroept. Alleen de relatie die daar gedelete wordt gebeurt met het type Employee, waardoor het misgaat. Maar ik weet inderdaad al in PersonMapper dat ik met Persons werk, dus zal ik maar expliciet aan GetDeleteStatement de naam van het domein object moeten meegeven.
Zoals ik dit stukje code lees is de naam van je collumn waarin je ID zit opgeslagen nou direct afhankelijk van de Naam van je Type. Dit lijkt me eigenlijk niet echt mooi om het zo te maken. Stel dat je nou later toch beslist dat je die Collumn name wilt veranderen? Het lijkt me dat je je Domein eigenlijk zo min mogelijk verbonden hoort te zijn met je Data opslag.

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


  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Je hebt wel een punt, maar toch denk ik dat dit geen gekke oplossing is. In mijn geval wordt de database geheel op basis van de domeinlaag gegenereerd. Ik heb dus geen reden om die columnname te veranderen. Als je dat wel zou willen doen zou je extra indirectie moeten toevoegen in de vorm van bijvoorbeeld een xml-bestand wat je uitleest om de mapping te genereren (heb ik ook aangedacht hoor). Even afgezien van het feit dat het weer extra werk is, betekent dit wel dat je handmatig de mapping tussen domein object en database moet bijhouden. Dan ben je nog verder van huis.
Je kan natuurlijk een GUI maken waar dit allemaal makkelijk kan, maar dat ligt niet in mijn bereik. Aangezien deze mapper alleen voor persoonlijk gebruik is (want niet goed genoeg ontworpen en getest) om eventueel ooit te verkopen, laat ik het maar even zo.
Overigens moet je een ergens een verbinding maken tussen domein en database. Maar het domein heeft in mijn geval ook helemaal geen last van en de domein programmeur hoeft zich helemaal niet druk te maken over de database.

[ Voor 13% gewijzigd door zoepercavia op 13-08-2003 12:06 ]

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • alley
  • Registratie: Mei 2002
  • Laatst online: 18-08 20:40

alley

ahuh

Ik ben het helemaal met zoepercavia eens,
als je in staat bent het datamodel en het domein op elkaar af te stemmen,
geeft een extra mapping alleen maar vertragingen en extra werk. Ik heb
het zelf ook zo toegepast.

I am always doing that which I can not do, in order that I may learn how to do it. (Pablo Picasso)


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

EfBe schreef op 13 August 2003 @ 10:11:
[hier stond iets doms door slecht lezen]
offtopic:
Gefeliciteerd trouwens, dat is je 1000e post :D

Professionele website nodig?


  • EfBe
  • Registratie: Januari 2000
  • Niet online
curry684 schreef op 13 August 2003 @ 15:15:
[...]

offtopic:
Gefeliciteerd trouwens, dat is je 1000e post :D
offtopic:
hehe :) (en dan zo'n stukje prutswerk afleveren :P

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


  • whoami
  • Registratie: December 2000
  • Laatst online: 21-08 22:54
offtopic:
We kunnen hem trashen, en dan kan je een mooie post maken voor dit historische event. :+

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Ontopic:
zoepercavia: wat je kunt doen is je acties 'sorteren' in je UnitOfWork en daarna uitvoeren. Wel wat extra werk, maar je kunt er dan wel zeker van zijn dat je alles in de juiste volgorde uitvoert. Maar wat ik ook in de andere thread zei over dezelfde mapper: class hierarchies opslaan in een relationeel model is vragen om moeilijkheden. De enige die het een beetje lukt is EntityBroker, maar ook daar valt alles om wanneer een waarde in een veld wijzigt.

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


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op 13 August 2003 @ 15:34:
offtopic:
We kunnen hem trashen, en dan kan je een mooie post maken voor dit historische event. :+
offtopic:
Ach, onder 'Otis' had ik al zo'n 3400 postings oid, mij maakt het niet uit :P (ik had niet eens gekeken of dat de 1000e was

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


  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
EfBe schreef op 13 augustus 2003 @ 15:35:
Ontopic:
zoepercavia: wat je kunt doen is je acties 'sorteren' in je UnitOfWork en daarna uitvoeren. Wel wat extra werk, maar je kunt er dan wel zeker van zijn dat je alles in de juiste volgorde uitvoert. Maar wat ik ook in de andere thread zei over dezelfde mapper: class hierarchies opslaan in een relationeel model is vragen om moeilijkheden. De enige die het een beetje lukt is EntityBroker, maar ook daar valt alles om wanneer een waarde in een veld wijzigt.
.

Hmm goed idee inderdaad om het persisteren van de relaties ook in unit of work te doen. Zijn daar overigens slimme algorithmes voor om te bepalen wat in welke volgorde gedaan moet worden door de unit of work? Of is het gewoon create, update en dan delete en dan create relation, update relation, delete relation?
Ik weet inderdaad dat het lastig is om class hierarchieen in een relationeel model op te slaan, maar het sprak me erg aan. Ik werk nu met database-wide keys (dmv een keygenerator). Dat betekent dus dat een Employee en een Person hetzelfde Id kunnen hebben (cq ze zijn hetzelfde object). Ik weet niet wat de technisch/theoretische bezwaringen hier van zijn, maar op dit moment werkt het heel aardig.
Het is minder handig als de database niet via de mapper wordt aangesproken (geen auto-increment keys immers), maar het biedt ook wel een aantal voordelen.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Zijn daar overigens slimme algorithmes voor om te bepalen wat in welke volgorde gedaan moet worden door de unit of work? Of is het gewoon create, update en dan delete en dan create relation, update relation, delete relation?
Het kan goed uit de klauwen lopen, omdat wanneer je bv een customer, een order en orderregels creeert het ook in die volgorde moet en niet in een andere, tenzij de FK fields NULLs kunnen bevatten en je dan eerst een NULL insert en dan een update eroverheen dendert met de PK value. maar dit kan ook niet altijd, wanneer het FK field deel uitmaakt van de PK. Je moet de FK relaties aflopen van FK table naar PK table. De FK table gerelateerde acties moet je eerst doen wanneer het gaat om deletes, de PK table gerelateerde acties moet je eerst doen wanneer het gaat om inserts (ik ga er vanuit dat je geen PK values Update want dat is onzin).

Je kan ook gewoon cascading deletes definieren in je sqlserver 2000 database, ben je van alle ellende af overigens :) PK deleten -> alle FK's deleten mee.

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

Pagina: 1